【调优案例】druid testOnBorrow参数问题
在性能优化调优数据库连接池配置调优效果修改前:spring.datasource.type = com.alibaba.druid.pool.DruidDataSourcespring.datasource.druid.initial-size = 20spring.datasource.druid.max-active = 50spring.datasource.druid.min-idle =
在性能优化调优数据库连接池配置
调优效果
修改前:
spring.datasource.type = com.alibaba.druid.pool.DruidDataSource
spring.datasource.druid.initial-size = 20
spring.datasource.druid.max-active = 50
spring.datasource.druid.min-idle = 20
spring.datasource.druid.max-wait = 5000
spring.datasource.druid.validation-query = select 1
spring.datasource.druid.test-on-borrow = true
spring.datasource.druid.test-on-return = true
spring.datasource.druid.test-while-idle = true
spring.datasource.druid.time-between-eviction-runs-millis = 60000
spring.datasource.druid.min-evictable-idle-time-millis = 60000
修改后:
spring.datasource.type = com.alibaba.druid.pool.DruidDataSource
spring.datasource.druid.initial-size = 3
spring.datasource.druid.max-active = 15
spring.datasource.druid.min-idle = 3
spring.datasource.druid.max-wait = 5000
spring.datasource.druid.validation-query = select 1
spring.datasource.druid.test-on-borrow = false
spring.datasource.druid.test-on-return = false
spring.datasource.druid.test-while-idle = true
spring.datasource.druid.time-between-eviction-runs-millis = 60000
spring.datasource.druid.min-evictable-idle-time-millis = 180000
优化的效果为:
- tps提升2倍+
- 服务器cpu从350% 下降为 40%
疑问点
因为主要调试的是连接数,但是连接数变小主要是减少数据库连接线程的切换,降低cpu使用,理论上cpu足够时,tps不会出现这么显著的提升,而且cpu降低的过于离谱
既然理论上解释不了,那就实践一波可能的影响因素
通过控制唯一变量的方式,首先修改 spring.datasource.druid.test-on-borrow
这个,将false
修改回 true
这个时候发现:
- tps仅比一开始提升1.5倍
- 服务器cpu仍然为350%
同样的方式试验其余变量
OK,初步断定参数 test-on-borrow
和 test-on-return
这两个配置项的影响
网上资料
mysql调优中关注的参数:
validationQuery
用来检测连接是否有效的sql,如果validationQuery为空,那么testOnBorrow、testOnReturn、testWhileIdle这三个参数都不会起作用,因为这三个参数都是通过执行参数validationQuery指定的SQL来验证数据库连接的有效性,配置参考:validationQuery=SELECT 1
testWhileIdle
建议配置为true。对性能影响很小,因为是定期检查。如果连接空闲时间大于timeBetweenEvictionRunsMillis指定的毫秒,就会执行参数validationQuery指定的SQL来检测连接是否有效。
testOnBorrow
建议配置为false。获取连接时执行validationQuery检测连接是否有效,这个配置会降低性能。
testOnReturn
建议配置为false。归还连接时执行validationQuery检测连接是否有效,这个配置会降低性能。
如果这4个参数都是按照上面建议进行配置,那么就不会有什么性能问题,
但是,下面这张压测表格 testOnReturn和testOnBorrow 不同值组合的情况下,5000次主键查询的耗时比较:
由这张压测结果表,我们可以得出如下结论:
testOnReturn和testOnBorrow都为false时性能最好。
如果任意一个参数为true(另一个为false),会导致性能下降5倍多。
testOnReturn和testOnBorrow对性能的影响几乎一样(因为它们都会通过执行参数validationQuery指定的SQL来校验连接的有效性)
事实上,这两个参数在druid中默认值就是false
arthas问题定位
通过apm链路监控,可以得到主要耗时在获取当前数据库连接耗时getConnection
,代码入口
@Override
public DruidPooledConnection getConnection() throws SQLException {
return getConnection(maxWait);
}
public DruidPooledConnection getConnection(long maxWaitMillis) throws SQLException {
init();
if (filters.size() > 0) {
FilterChainImpl filterChain = new FilterChainImpl(this);
return filterChain.dataSource_connect(this, maxWaitMillis);
} else {
return getConnectionDirect(maxWaitMillis);
}
}
安装arthas
并追踪链路耗时
wget https://alibaba.github.io/arthas/arthas-boot.jar
java -jar arthas-boot.jar
通过一层层定位并结合druid代码
trace com.alibaba.druid.pool.DruidDataSource pollLast '#cost > 10' -n 3
发现在代码中
需要加载类 com.mysql.jdbc.MySQLConnection
,而当前mysql-connector 8.X的驱动中并不存在,Utils.loadClass方法类加载生吞了异常,所以代码逻辑会频繁对不存在的类进行类加载
trace com.alibaba.druid.util.Utils loadClass '#cost > 10' -n 3
接着实验执行10000次,当类存在时需要时间40ms+,当类不存在时需要3500ms,相差两个量级
优化
其实在druid的issue 中也有人提到此问题,且在1.1.24版本已经解决了该问题
所以在前面针对testOnReturn和testOnBorrow 性能5倍的优化是因为druid 1.1.10中的bug的结论,其实试验发现性能大概损耗不到10%,并没有前面得到的结论这么离谱
该问题mysql的官方建议配置项将配置 test-on-borrow
和 test-on-return
设置为false
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)