You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何调试HikariCP连接丢失?Play 2.6.10连接泄漏排查求助

解决Play 2.6.10 + HikariCP连接泄漏的实战思路

嘿,从你给出的日志和场景来看,这个连接泄漏问题确实有点棘手——毕竟你明明用了Play的withConnection,理论上连接应该自动归还池里才对。结合你提到的setNetworkTimeout这个特殊操作,我梳理几个大概率的排查方向和解决步骤:

一、先怀疑你的setNetworkTimeout操作

你说每个连接都要调用这个方法,设置低至10秒的超时,这很可能是罪魁祸首:

  • 旧版本的MySQL JDBC驱动(比如5.1.x系列)在处理setNetworkTimeout时存在已知bug,会导致连接的内部状态紊乱,HikariCP在尝试回收连接时无法正确识别,直接把这个连接当成“不可用”丢弃,但又没从active计数里减掉,久而久之池就被耗尽了。
  • Play的withConnection是靠try-finally来保证归还的,但如果在finally块执行归还时,因为之前的setNetworkTimeout导致连接抛出异常,这个异常可能被Play的封装层静默吞掉,结果就是连接没还回去。

验证方法:

  1. 先临时把setNetworkTimeout的代码注释掉,跑个几天看看还会不会泄漏。如果问题消失,那基本实锤是这个操作的锅。
  2. 赶紧升级你的mysql-connector-java版本,建议直接更到8.0.x的稳定版,新驱动修复了不少网络超时相关的bug。

二、检查Play与Hikari的配置兼容性

Play 2.6.x默认用Hikari,但有时候配置冲突也会搞出问题:

  • 打开你的application.conf,核对下这些参数:
    db.default.hikaricp.leakDetectionThreshold = 60000 # 你已经开了,这个没问题
    db.default.hikaricp.maximumPoolSize = 10 # 日志显示total=10,和你的配置一致
    db.default.hikaricp.connectionTimeout = 30000 # 确保连接超时不要设得太长
    db.default.hikaricp.maxLifetime = 1800000 # 建议设成比MySQL的wait_timeout小,比如30分钟
    
  • 再确认下有没有其他地方手动获取过连接(比如绕过Play的封装直接拿Hikari的连接),如果有,是不是没调用close()归还?虽然你说只用了withConnection,但这种小疏忽很容易犯。

三、把调试粒度拉满,定位泄漏点

既然已经开了leakDetectionThreshold,可以再优化下日志来抓细节:

  1. 把阈值调小一点,比如设成30000(30秒),这样不用等几天,只要有连接超过30秒没归还,就能立刻抓到堆栈,方便你定位对应的业务代码。
  2. 打开HikariCP的DEBUG日志,这样能看到每一个连接的获取、归还、销毁日志,对比active连接数的变化,就能清楚看到是哪些连接只拿不还。
  3. 下次出现连接耗尽时,除了看阻塞的线程,还要找那些持有active连接的线程——它们可能卡在慢查询、第三方API调用或者死锁上,导致连接被长时间占用,这也算一种“隐性泄漏”。

四、绕过Play的封装,直接用Hikari管理连接

如果怀疑是Play的withConnection和Hikari的兼容性问题,可以试试直接用HikariDataSource来管理连接:

import com.zaxxer.hikari.HikariDataSource
import javax.inject.Inject
import java.sql.Connection
import java.util.concurrent.Executors

class ActionSummary @Inject()(hikariDS: HikariDataSource) {
  def listByStripe() = {
    var conn: Connection = null
    try {
      conn = hikariDS.getConnection()
      // 如果一定要设置超时,这里加,但记得用最新驱动
      conn.setNetworkTimeout(Executors.newSingleThreadExecutor(), 10000)
      // 你的查询逻辑写在这里
    } finally {
      if (conn != null) {
        try {
          conn.close() // 手动归还,确保万无一失
        } catch {
          case e: Exception => 
            // 捕获关闭时的异常,别让它掩盖了原问题
            e.printStackTrace()
        }
      }
    }
  }
}

这种方式更直接,能排除Play封装层的干扰,如果这样改了之后不再泄漏,那就是Play和Hikari的交互有问题。

五、检查MySQL服务器的连接配置

有时候问题不在应用端,而是MySQL主动断开了连接:

  • 查看MySQL的wait_timeout和interactive_timeout参数,如果这两个值比Hikari的maxLifetime小,MySQL会主动断开闲置的连接,但Hikari池里还以为这个连接可用,后续使用时会抛出异常,可能导致连接无法正常归还。
  • 把Hikari的maxLifetime设成比MySQL的wait_timeout小10%左右,比如MySQL的wait_timeout是8小时,Hikari就设成7小时10分钟,让Hikari在MySQL断开前主动回收连接。

内容的提问来源于stack exchange,提问作者wingedsubmariner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:54:14