DB | 连接池

543 阅读5分钟

1、是什么

程序启动时,先创建好一定数量的数据库连接,并将这些连接组成一个连接池,而后由程序动态地对池中的连接进行申请、时候用、释放;

2、为什么

如果不使用连接池机制,那么,程序每次对数据进行操作时,都需要创建一条数据库连接,数据操作完之后,又要将连接进行释放,这样将极大的浪费数据库的资源,并且极易造成数据库服务器内存溢出和宕机;

mysql连接的建立

首先,后端通过TCP和数据库服务器建立连接,TCP连接的建立本身就要消耗资源;

且每个连接都会创建一个线程,线程的创建和销毁也是非常耗资源的,尽管有线程池的存在;

且线程需要栈空间的,ulimis -s查看得知,ubuntu默认的栈空间大小是8M。

3、怎么做

最小连接数(即空闲连接数):指就算没有操作数据库,也保持了这么多的连接;

最大连接数:指程序所能建立的最多连接数,超过这个数量时,后面的数据库操作将被阻塞,进入等待队列;

4、数据池大小如何设置才合理?

连接池到底才设多大?

并发一定快吗?不一定哦,每个CPU核心同一时刻只能运行一个线程而已。就单核CPU而言,多线程并发并不一定比串行快;

  • 给定一颗CPU核心,其顺序执行A和B永远比通过时间分片“同时”执行A和B要快,这是一条计算机科学的基本法则。
  • 一旦线程的数量超过了CPU核心的数量,再增加线程数系统就只会更慢,而不是更快,因为这里涉及到上下文切换耗费的额外的性能。
  • 在这一时间段(即"I/O等待")内,线程是在“阻塞”着等待磁盘,此时操作系统可以将那个空闲的CPU核心用于服务其他线程。所以,由于线程总是在I/O上阻塞,我们可以让线程比CPU核心多一些,这样能够在同样的时间内完成更多的工作。
  • 公式:连接数 = ((核心数 * 2) + 有效磁盘数);这一公式开始测试你的应用,寻找最合适的连接数值。

MySQL是单进程多线程的,新到来一个连接后,会为该线程分配一个线程。如果服务器已经有空闲的线程被缓存了,则直接使用。如果没有缓存可用的线程,则重新创建一个线程给该连接使用。

这些线程是并发的;

so,公理:你的应用需要一个小连接池,和一个充满了等待连接的线程的队列

请注意

连接池的大小最终与系统特性相关。

比如一个混合了长事务和短事务的系统,通常是任何连接池都难以进行调优的。最好的办法是创建两个连接池,一个服务于长事务,一个服务于短事务。

再例如一个系统执行一个任务队列,只允许一定数量的任务同时执行,此时并发任务数应该去适应连接池连接数,而不是反过来。

5、连接池爆满排查

mysql:show processlist

psql:select pid,datname,usename,query FROM pg_stat_activity;

可以追踪那个用户,在哪个数据库,执行了什么语句,导致连接一直被占用,而无法释放;

6、关于线程池

线程池的大小设置

要避免不必要的上下文切换,很耗时的;

CPU密集型应用,线程池大小设置为N+1(N为CPU核数)

IO密集型应用,线程池大小设置为2N+1,这里2倍,即能充分利用CPU,又不至于导致太多的线程切换,消耗资源;

为什么+1?

即使当计算密集型的线程偶尔由于缺失故障或者其他原因而暂停时,这个额外的线程也能确保CPU的时钟周期不会被浪费。

只是提供了一个理论值,具体的设置值还需要根据具体的业务和环境,经过多番测试之后得出;

数据库的架构模式

mysql是单进程,多线程的,每个连接建立一个线程;

psql是多进程的,每个连接建立一个进程,这个进程又是单线程的;

这也就是为什么连接池要设置成2*CPU核数+1了。

对于4核CPU,只需要10就够了;设太大,占内存不说,还慢;

1、数据库读取数据是IO操作,会发生IO阻塞。也就是这条连接对应的线程阻塞了,这时要进行线程切换了;

2、如果这时有几十条连接,也就是几十个线程在并发,将会造成很多不必要的上下文切换;

什么叫不必要的切换,就是一个线程运行的好好的,又不是发生阻塞了,你切换它干嘛!

明确一点,切换会造成性能的消耗,也就是会变慢;

也不能设置的太少,不然线程都IO阻塞了,CPU就空闲了,利用率就不高了;

3、因此,需要后端设置连接池,并设置合理的size;

将超过size部分的请求阻塞起来,等连接池有空闲连接了,再唤醒;

思考:服务器还有其他线程呢?单考虑数据库的合理吗?

只能说,这只是作为理论指导吧!