序言
对后台应用程序而言几乎离不开操作数据库,而操作数据库绝对是要跟连接池 pool 打交道的。
简述 pool
任何一个应用程序想要操作数据库,必须首先与数据库之间建立一个连接,然后将诸如 SQL 命令等交由数据库解析并执行,最后断开这个连接。但是连接的建立与断开都是会大量消耗资源的,为了避免这个问题,连接池 pool 因此出现,pool 简单来说就是将连接缓存起来,这样下一次应用程序需要操作数据库的时候就不要重新建立和销毁连接了,也许你会问我每次对数据库的操作都是由具体的业务场景而决定的,为什么可以使用 pool 中已经使用过的连接呢?
这其实很好理解,连接如同桥梁,是基础设施,而不同的业务操作换言之就是需要执行的不同的 SQL ,就是普通的数据运到终点了交由数据库执行就是了。
配置 pool
下面以 sequelize 中的连接池配置为例,具体说明,其实不论你使用什么编程语言、什么依赖库,你都会发现连接池的配置是极其相似的。
连接池 pool :
max: 连接池中的最大连接数
min: 连接池中的最小连接数
idle: 一个连接在释放前可空闲的时间
evict: 驱逐陈旧连接的时间间隔
acquire:最大连接超时时间
max:连接池中的最大连接数。
上图是某款 mysql 云数据库的规格,红色圈中可以明显的看到,连接数为 2000 ,这个连接数是数据库本身的限制,最多只让你同时建立 2000 个左右的连接(数字并不是绝对准确的)。
连接池中的最大连接数 max 能否超过这个数呢? 当然是可以的,并发量小的时候不会有任何问题,但是并发量大了真的需要连接超出数据库允许的连接数时自然就会抛出一堆异常,所以还是不要将 pool 中 max 的值设置为超过数据库的限制。
哦,对了,如何查询自己使用的数据库的最大连接数呢? 执行以下指令:
show variable like 'max_connections' ;
除了数据库最大连接数外,还不得不提另一个数据,那就是数据库实际响应过的最大连接数:
show status like 'Max_used_connections' ;
如果你发现这个数值与 pool 设置中 max 的值接近或者大于后者,那么说明,max 的值极有可能需要上调,为啥? 你设置的 max 为 200 ,结果你一查数据库实际响应过的最大连接数比 200 还多,这就说明连接池中的连接数在某种情况下是不够用的。
min: 连接池中的最小连接数。
之前我们说过,连接池 pool 的作用是缓存连接,而如果 min 值设为 0 ,这个时候连接池中是不会缓存任何连接的,那你是不是又会问,那我要 pool 何用?现在换一个角度来看,如果 min 值设置一个大于 0 的数,那么连接池中不论什么情况下都会至少缓存这么多连接,而如果我明明知道某些时候是肯定不会操作数据库的,那你缓存了这么多连接其实还是在浪费资源,毕竟站了位置啥也没干。所以 min 值的设置也是有讲究的,对于某一个高频的应用而言,我们几乎可以认为连接断断续续也好仍然是一直会使用的,那么我们就可以 min 值设置为一个非零的数,反之,我的应用就是一个很低频的情况比如某些定时任务每天一个固定的时间点执行下任务就完了,这一天的其他时间不会再使用连接,那么这种情况将 min 值设为 0 是更合理的。
idle: 一个连接在释放前可空闲的时间。
连接池 pool 中的某个连接使用完毕了可以空闲多久的时间,如果空闲的这个时间段内,有其他对数据库操作的请求进来了,这个时候这个连接是可以继续使用的,也就是说恭喜你又是一次物尽其用啊。如果直到空闲之间结束,这个连接仍然没有后续的请求使用,那么不好意思,弃之。
evict: 驱逐陈旧连接的时间间隔。
evict 和 idle 是需要结合起来使用的,上面说过,一个连接在可空闲的时间 idle之后仍然存于空闲状态,这个连接是要被释放掉的,但是由谁要释放、怎么释放呢? 答案是一套不断轮询的机制,而 evict 值正是设置了轮询的时间间隔,每隔一定时间去检查连接池中的连接是不是空闲了,空闲之后又是不是需要被释放,所以超出空闲时间的连接并不是立即马上就被释放掉了。
再看一个有意思的情况,最小连接数 min 值不为零,同时设置了 idle 和 evict,而某段时间内不需要使用连接,这时候连接池一直维持着最小数量的连接数,并且这些连接一直是空闲并超时的情况,而 evict 又会不断的释放掉这些连接,这样连接数不够了但为了保持指定的最小数量,怎么办,新增连接呗,如此循环,没事干瞎折腾,是不是很有意思。
acquire:最大连接超时时间。
连接池 pool 的最大连接数 max 设为了 200,而突然某个时刻,并发量过大,导致需要使用的连接数为 220 ,那么这多出来的 20 个连接怎么办,立马报错不允许建立连接吗? 并不是,因为其它的连接很有可能执行完了任务是可以交由你继续使用的,所以这多出来的连接就要等待了,当然肯定不会是一直等待,acquire 就是你设置的最大的等待时间,超出了这个时间还没有能够建立连接,那么不好意思,注定是没你的份了。
结语
以上重点关注了连接池 pool 中的五个参数的设置,总结起来的话,我们可以将使用场景以频率和并发量两个维度划分,对于低频场景,pool 中的最小连接数 min 设为 0 就行了,反之,高频情况下根据实际的业务状况设为一个大于零的值。而对于并发量,低并发量没啥好说的,高并发量呢,最大连接数 max 的值
适当设高点,acquire 超时时间也可以适当延长。
最后,不要断章取义、生搬硬套上面的这些内容,具体怎么配置连接池一定要仔细考虑具体的场景。