问题出现得很突然,日志倒是留得挺全。服务跑十二小时后开始报等待连接超时,重启就好,HikariCP 的活跃连接数从早上开始单调上涨,压测环境复现不了,只能等生产上跑够时间。
刚开始盯着「异步线程里拿了连接,在外层线程关闭」,折腾了半个多小时,排掉了。
原因不止一个,得分开看。某条异常分支没有 close,连接漏在栈里。少数情况下是手动提交事务回滚遗漏,连接状态没复位。
少数情况下是流式查询没读完结果集,连接一直挂着。
第一件事是打开泄漏检测并设阈值
curl -s -X POST http://10.0.0.11:8080/actuator/env -d '{"name":"spring.datasource.hikari.leak-detection-threshold","value":"20000"}'
随后按时间序列看活跃连接走势
curl -s http://10.0.0.11:8080/actuator/metrics/hikaricp.connections.active
接着抓线程栈定位未关闭的调用点
jstack $(pgrep -f order-service) > /tmp/js.txt && grep -c HikariPool /tmp/js.txt
剩下的就是检查是否有流式查询未消费完
grep -rn 'useCursorFetch\|setFetchSize' src/main/java | head
改完先别撤,确认这几项。打开检测后日志能打出泄漏堆栈,修复后活跃连接数一整天保持平稳,不再随时间单调上涨。
补一句。泄漏检测有性能开销,只在排查期打开;真正的改法是把连接获取收进模板方法,别让每条分支各写一遍 close。报错文案容易误导,真正的原因往往在相邻那一层的日志里。
