解决dbcp2线程池GenericObjectPool.borrowObject阻塞问题

问题:

在我们测试环境,在测试量大的时候偶尔就出现所有接口超时问题;

开始排查,挑了其中一个接口详细加上日志,发现调service方法执行简单的保存SQL竟然耗时好几分钟,故而开始怀疑是数据库问题,单后面看日志发现在几分钟后所有SQL又在几十毫秒里执行完了,而且也没听其他人员反馈数据库问题,故觉得应该不大可能是数据库问题。

执行命令  jstack <pid> >jstack01.text;

堆栈信息显示多个线程 WAITING

那只能查看dbcp2的源码了,看看这到底干了啥

可以看到 borrowObject 里会先调create方法,但create方法首先会判断已经创建的连接数是否大于最大连接数,如果大于则直接返回null;

关键就是这,看了下我们系统目前线程池的配置没有配MaxTotal值,刚开始我以为是-1,后面通过看源码发现默认是等于8。

先贴下我们之前dbcp配置:

jdbc.maxIdle=100
jdbc.minIdle=10
jdbc.initialSize=10
jdbc.driver=com.mysql.jdbc.Driver
jdbc.timeBetweenEvictionRunsMillis=80000
jdbc.minEvictableIdleTimeMillis=90000
jdbc.poolPreparedStatements=true
jdbc.maxOpenPreparedStatements=50
jdbc.removeAbandonedTimeout=90
jdbc.testWhileIdle=true
jdbc.testOnBorrow=true
jdbc.testOnReturn=true
jdbc.validationQuery=SELECT 1+1

也就是说当连接个数创建到>8的时候只能从空闲队列中获取,如果没设置maxWaitMillis参数,则就一直等待,直到获取成功为止;

解决方法:

所以知道了问题所在就好办了,重新修改配置如下:

jdbc.maxTotal=120   (最好大于maxIdle)
jdbc.maxIdle=100
jdbc.minIdle=10
jdbc.initialSize=10
jdbc.driver=com.mysql.jdbc.Driver
jdbc.timeBetweenEvictionRunsMillis=80000
jdbc.minEvictableIdleTimeMillis=90000
jdbc.poolPreparedStatements=true
jdbc.maxOpenPreparedStatements=50
jdbc.removeAbandonedTimeout=90
jdbc.testWhileIdle=true
jdbc.testOnBorrow=true
jdbc.testOnReturn=true
jdbc.validationQuery=SELECT 1+1
jdbc.maxWaitMillis=60000  (控制获取不到连接时超时时间,避免无限等待)
jdbc.logAbandoned=true
jdbc.removeAbandonedOnMaintenance=true

猜你喜欢

转载自my.oschina.net/woter/blog/1631047