一.背景
应用在执行完某个复杂业务,主要包含20几个查询SQL的操作后,会导致数据库连接池一直升高
druid版本:1.2.11
druid配置文件:
spring.datasource.druid.maxActive=100 spring.datasource.druid.initialSize=20 spring.datasource.druid.maxWait=6000 spring.datasource.druid.minIdle=20 spring.datasource.druid.timeBetweenEvictionRunsMillis=6000 spring.datasource.druid.keepAlive=true spring.datasource.druid.minEvictableIdleTimeMillis=30000 spring.datasource.druid.validationQuery=select 1 from dual spring.datasource.druid.testWhileIdle=true spring.datasource.druid.testOnBorrow=false spring.datasource.druid.testOnReturn=false spring.datasource.druid.poolPreparedStatements=true spring.datasource.druid.maxOpenPreparedStatements=20
二.排查过程
logging.level.com.alibaba.druid=debug
打开druid debug日志,发现如下报错
3.进行本地调试跟踪发现druid 的shrink 方法在保活处理时存在问题。
System.arraycopy(connections, removeCount, connections, 0, poolingCount - removeCount);
Arrays.fill(connections, poolingCount - removeCount, poolingCount, null);
shrink方法中这两行代码从connections[]数组移除的数据库连接,和shrink方法中这两行代码上面的添加到keepAliveConnections[]数组中的连接不一致
异常结果:
- 正常的连接引用直接丢失,也就是既不在connections[]数组,也不在keepAliveConnections[]数组
- 会不断触发新建数据库连接,导致泄露
三.解决方案
1.关闭keepAlive
2.升级Druid版本到1.2.20