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部分的请求阻塞起来,等连接池有空闲连接了,再唤醒;
思考:服务器还有其他线程呢?单考虑数据库的合理吗?
只能说,这只是作为理论指导吧!