调优案例druid testOnBorrow参数问题

Posted sysu_lluozh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了调优案例druid testOnBorrow参数问题相关的知识,希望对你有一定的参考价值。

在性能优化调优数据库连接池配置

调优效果

修改前:

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

优化的效果为:

  1. tps提升2倍+
  2. 服务器cpu从350% 下降为 40%

疑问点

因为主要调试的是连接数,但是连接数变小主要是减少数据库连接线程的切换,降低cpu使用,理论上cpu足够时,tps不会出现这么显著的提升,而且cpu降低的过于离谱

既然理论上解释不了,那就实践一波可能的影响因素

通过控制唯一变量的方式,首先修改 spring.datasource.druid.test-on-borrow 这个,将false 修改回 true
这个时候发现:

  1. tps仅比一开始提升1.5倍
  2. 服务器cpu仍然为350%

同样的方式试验其余变量

OK,初步断定参数 test-on-borrowtest-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-borrowtest-on-return 设置为false

以上是关于调优案例druid testOnBorrow参数问题的主要内容,如果未能解决你的问题,请参考以下文章

redigo的redis.Pool 配置参数调优

Druid调优指南(一)- Historical

JVM调优参数方法工具以及案例总结

面试官:如何进行 JVM 调优(附真实案例)

面试官:如何进行 JVM 调优(附真实案例)

面试官:如何进行 JVM 调优(附真实案例)