配置:
testWhileIdle=true testOnBorrow=false testOnReturn=false keepAlive=true
mysql服务端wait_timeout=60分钟。 默认情况下, 每60秒通过"select 1‘’检测一次空闲连接。 然而, 部分空闲连接依然给mysql杀掉。
从mysql看空闲的连接的情况, select * from infomation_schema.processlist order by time desc limit 10; 发现大量的连接空闲时间超过10几分钟(Command=Sleep)。(理论上空闲时间不超过1分钟)
开启mysql的日志, 没发现保活查询语句select 1 在客户端抓包, 也常时间没发现有tcp包发往mysql。
查询代码MySqlValidConnectionChecker.isValidConnection, 发现即使配置了validationQuery, 保活机制依然默认采用mysql_ping。
这个设置很不合理且没有文档说明。 这个机制只能用于检测连接是否有效,对于testOnBorrow来说可能比较合适。 但对于testWhileIdle来说, 并不起作用,因为它不会重置连接的空闲时间。
1.1.14? 看代码最新版本也是一样的
而且, 禁用usePingMethod这个参数,并没有在wiki上说明。
禁用usePingMethod后,经过调试发现,客户端30分钟才会发一次SELECT 1, 预期是1分钟(默认配置)(update: 30分钟才发心跳,是因为minEvictableIdleTimeMillis设置了30分钟。。)。 并且, 配置了MinIdle是30, 最后只剩下一条连接了!
原提问者GitHub用户zhangever
主要可能的原因有几种:
数据库本身关闭或挂起了连接
部分数据库在一段时间内没有活动后,会自动关闭或挂起连接。
这时即使Druid检验了连接,也会发现连接已失效。
检查时数据库不可用,造成校验失败
如果在Druid校验连接时,数据库短暂不可用,这时校验也会失败,标识连接失效。
TestWhileIdle配置不合理
如果timeBetweenEvictionRunsMillis(校验间隔)设置太长,就可能间隔时间内数据库主动断开连接。
数据库配置限制了空闲连接的存活时间
部分数据库可以配置空闲连接的存活时间,当超过设置值后会自动失效。
最终结论: 心跳方式不管是mysql_ping还是SELECT 1, 都可以重置连接的空闲时间。 然后,保活线程是1分钟执行一次,但只对空闲时间超过minEvictableIdleTimeMillis的连接发心跳。
我们之前minEvictableIdleTimeMillis设置是30分钟, 所以30分钟才会看到一次心跳。 而mysql服务端不知道为何, 对于超过30分钟的连接会直接kill掉。
原回答者GitHub用户zhangever
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。