数据库连接池配置最佳实践
引言
在日常项目开发和问题排查中,发现一些问题是因为数据库连接池配置不合理导致,这里以druid连接池为例来阐述几个参数的重要性及如何避免踩坑,
虽然下面提到的都是druid的配置项,但多数连接池(不限于数据库)其实也都有类似的配置,基本用法和场景均可借鉴。
配置参考
maxActive=50(根据业务实际情况调整)
minIdle=5(根据业务实际情况调整)
initialSize=5 (根据业务实际情况调整)
maxWait=3000
validationQuery=SELECT 1
validationQueryTimeout=1000
testWhileIdle=true
testOnBorrow=false
timeBetweenEvictionRunsMillis=60000
minEvictableIdleTimeMillis=300000
1. initialSize
初始化连接数:连接池启动时创建的初始化连接数量,默认值0
初始连接数,这里的初始指的是第一次getConnection的时候,而不是应用启动的时候。
画外音:这就是为什么第一次进行数据库操作的时候,响应会比较慢的原因,创建数据库连接是很耗时的,所以初始化连接并不是越多越好
配置过大容易导致服务发布首次请求出现大量超时
参考公式:QPS /(1000/RT) + N
注意: 此处 QPS 和 RT 为单个应用端统计。RT为请求响应耗时(单位ms)统计平时的最大 QPS 和此时的 RT,以此计算 minIdle,并设置 initialSize = minIdle。
统计峰值时的 QPS 和此时的 RT,以此计算 maxActive。
具体可通过JMX查看服务Druid 实际的连接池状况, 重点关注 ActiveCount:活动连接数,PoolingCount:池子中的连接数。并根据实际情况考虑调整。
案例一:
initialSize=0(不配置默认为0)
这种配置会导致服务启动时,大量请求进来没有足够的连接使用而去获取链接,导致出现很多获取连接超时异常
案例二:
initialSize=100
maxActive=100
这种配置会导致服务启动后首次请求响应会比较慢,可能会导致超时
2.maxWait
参数表示从连接池获取连接的超时等待时间,单位毫秒,需要注意这个参数只管理获取连接的超时。获取连接等待的直接原因是池子里没有可用连接,
具体包括:连接池未初始化,连接长久未使用已被释放,连接使用中需要新建连接,或连接池已耗尽需等待连接用完后归还。这里有一个很关键的点是 maxWait 未配置或者配置为 0 时,表示不设等待超时时间
案例一
maxWait=0
正常流量下业务没有发现任何问题,但突发大流量涌入时,造成连接池耗尽,所有新增的DB请求处于等待获取连接的状态中。由于 maxWait=0 表示无限等待,在请求速度大于处理速度的情况下等待队列会越排越长,
最终业务上的表现就是业务接口大量超时甚至可能打满容器线程造成服务不可用,流量越大造成实际吞吐量反而越低
推荐配置: 内网(网络状况好) 1200ms;网络状况不是特别好的情况下推荐大于等于 1200ms,因为tcp 建连重试一般是 1 秒。
3.validationQuery
当Druid遇到testWhileIdle,testOnBorrow,testOnReturn时,就会验证连接的有效性,验证规则如下:
如果有相关数据库的ValidConnectionChecker,则使用ValidConnectionChecker验证(Druid提供常用数据库的ValidConnectionChecker,包括MSSQLValidConnectionChecker,MySqlValidConnectionChecker,OracleValidConnectionChecker,PGValidConnectionChecker);
如果没有ValidConnectionChecker,则直接使用validationQuery验证;
Druid用来测试连接是否可用的SQL语句,默认值每种数据库都不相同:
Mysql:SELECT 1;
SQLSERVER:SELECT 1;
ORACLE:SELECT 'x' FROM DUAL;
PostGresql:SELECT 'x';
4.testWhileIdle,testOnBorrow,testOnReturn
testWhileIdle,这一项官方建议设置为true,如果
testOnBorrow
没有被置为true,则会进行testWhileIdle
的检查,检查时会判断当前连接对象距离上次被使用的时间是否超过规定检查的时间,若超过,则进行检查一次,这个检查时间通过
timeBetweenEvictionRunsMillis
来控制,默认60s。testOnBorrow,官方不建议设置
testOnBorrow
为true,默认为false,如果开启了testOnBorrow,则每次请求都会去测试连接是否可用,会极大影响服务性能
testOnReturn,这个跟testOnBorrow一样,官方默认不开启,也不建议开启,影响性能,理由参考对testOnBorrow的解释。
5.timeBetweenEvictionRunsMillis
作为验证连接是否有效的时间周期,如果testOnBorrow==false并且testWhileIdle==true,则在应用获取连接的时候会判断连接的空闲时间是否大于timeBetweenEvictionRunsMillis,如果大于则会验证该连接是否有效。
6.minEvictableIdleTimeMillis
连接池中连接可空闲的时间
timeBetweenEvictionRunsMillis和minEvictableIdleTimeMillis一起使用,每timeBetweenEvictionRunsMillis毫秒检查一次连接池中空闲的连接,
把空闲时间超过minEvictableIdleTimeMillis毫秒的连接断开,直到连接池中的连接数到minIdle为止主要把这两个参数加上就好。
7.validationQueryTimeout
validationQueryTimeout
仅控制validationQuery
的超时