HikariCP:为啥连接泄漏和释放导致新数据库连接的“连接尝试超时”?

Posted

技术标签:

【中文标题】HikariCP:为啥连接泄漏和释放导致新数据库连接的“连接尝试超时”?【英文标题】:HikariCP: Why does connection leak and unleak result in "connection attempt timed out" for new DB connection?HikariCP:为什么连接泄漏和释放导致新数据库连接的“连接尝试超时”? 【发布时间】:2021-09-09 17:07:28 【问题描述】:

我正在运行一个使用默认 HikariCP 作为数据源的 Spring Boot Java 应用程序:

Hikari 版本 - 3.4.5 Spring Boot 版本 - 在 AWS EKS 中运行的 2.4.5 JDBI 版本 - 3.9.1 数据库 - AWS RDS Postgres

我的 Spring 应用程序失去响应,因为它失去了 Hikari 池中的所有连接。这不是确定性地发生的,但是一旦开始发生,唯一可能的恢复就是通过重新启动。

光配置:

池不断丢失连接,无法重新连接,留下total=0 连接。

06-23 08:14:33.242 [HikariPool-1 管家] 调试 HikariPool - HikariPool-1 - 池统计信息(总计 = 10,活动 = 1,空闲 = 9,等待 = 0) 06-23 08:15:07.189 [HikariPool-1 管家] 调试 HikariPool - HikariPool-1 - 池统计信息(总计 = 10,活动 = 1,空闲 = 9,等待 = 0) 06-23 08:15:07.190 [HikariPool-1 管家] 调试 HikariPool - HikariPool-1 - 填充池已跳过,池处于足够水平。 06-23 08:15:32.785 [HikariPool-1 连接更紧密] DEBUG PoolBase - HikariPool-1 - 关闭连接 org.postgresql.jdbc.PgConnection@58f866df :(连接被驱逐) 06-23 08:15:41.278 [HikariPool-1 管家] 调试 HikariPool - HikariPool-1 - 池统计信息(总计 = 9,活动 = 1,空闲 = 8,等待 = 0) 06-23 08:15:49.809 [HikariPool-1 连接添加器] DEBUG PoolBase - HikariPool-1 - 无法创建/设置连接:连接尝试超时。 06-23 08:15:49.809 [HikariPool-1 连接添加器] 调试 HikariPool - HikariPool-1 - 无法从数据源获取连接 org.postgresql.util.PSQLException:连接尝试超时。 在 org.postgresql.Driver$ConnectThread.getResult(Driver.java:422) 在 org.postgresql.Driver.connect(Driver.java:267) 在 com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:138) 在 com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:358) 在 com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:206) 在 com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:477) 在 com.zaxxer.hikari.pool.HikariPool.access 100 美元(HikariPool.java:71) 在 com.zaxxer.hikari.pool.HikariPool$PoolEntryCreator.call(HikariPool.java:725) 在 com.zaxxer.hikari.pool.HikariPool$PoolEntryCreator.call(HikariPool.java:711) 在 java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) 在 java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) 在 java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) 在 java.base/java.lang.Thread.run(Thread.java:829) 06-23 08:15:49.810 [HikariPool-1 连接添加器] 调试 HikariPool - HikariPool-1 - 连接添加失败,休眠与退避:250 毫秒 06-23 08:15:49.816 [HikariPool-1 连接更紧密] DEBUG PoolBase - HikariPool-1 - 关闭连接 org.postgresql.jdbc.PgConnection@7303422e: (连接被驱逐) (在更多这些之后) 06-23 10:23:21.731 [ForkJoinPool-1-worker-7] 调试 HikariPool - HikariPool-1 - 添加连接省略,等待 2,队列 10 06-23 10:23:55.883 [ForkJoinPool-1-worker-7] 调试 HikariPool - HikariPool-1 - 超时失败统计信息(总计 = 0,活动 = 0,空闲 = 0,等待 = 0) 06-23 10:23:55.883 [pool-3-thread-4] 调试 HikariPool - HikariPool-1 - 超时失败统计信息(总计 = 0,活动 = 0,空闲 = 0,等待 = 0) 06-23 10:23:55.883 [HikariPool-1 管家] DEBUG HikariPool - HikariPool-1 - 池统计信息(总数=0,活动=0,空闲=0,等待=0) 06-23 10:23:55.883 [HikariPool-1 管家] 调试 HikariPool - HikariPool-1 - 填充池已跳过,池处于足够水平。

FWIW,我找到了泄漏检测的日志,但它们后面是 unleaked 日志。泄漏阈值设置为 20 秒。

06-23 08:07:04.506 [HikariPool-1 管家] WARN ProxyLeakTask - 在线程 ForkJoinPool-1-worker-1 上为 org.postgresql.jdbc.PgConnection@58f866df 触发连接泄漏检测,堆栈跟踪如下 java.lang.Exception:检测到明显的连接泄漏 在 com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:128) 在 org.springframework.jdbc.datasource.DataSourceUtils.fetchConnection(DataSourceUtils.java:158) 在 org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:116) 在 org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy$TransactionAwareInvocationHandler.invoke(TransactionAwareDataSourceProxy.java:223) 在 com.sun.proxy.$Proxy119.getAutoCommit(未知来源) 在 org.jdbi.v3.core.transaction.LocalTransactionHandler.isInTransaction(LocalTransactionHandler.java:118) 在 org.jdbi.v3.core.Handle.(Handle.java:76) 在 org.jdbi.v3.core.Jdbi.open(Jdbi.java:309) (特定于应用程序的堆栈跟踪) ... 06-23 08:07:04.527 [ForkJoinPool-1-worker-1] INFO ProxyLeakTask - 先前报告的线程 ForkJoinPool-1-worker-1 上泄漏的连接 org.postgresql.jdbc.PgConnection@58f866df 已返回池(未泄漏)

当我重新部署应用程序时,它完美启动,并且该应用程序的其他实例正常工作,所以我已经排除了网络和RDS方面的问题。

我的问题:

    连接泄漏是问题的根源吗?因为他们是unleaked,Hikari 不应该能够回收连接并创建新连接吗?有没有办法确认根本原因? 泄漏并不经常发生,但当它们发生时,它们会针对多个请求开始发生,直到应用程序变得无响应。有没有办法找出为什么请求开始花费超过 20 秒的时间? 哪些配置更改有助于进行更多诊断并进一步解决问题?

谢谢。

【问题讨论】:

【参考方案1】:

如果你不关闭连接,hikari 就无法知道你需要/想要关闭它

你必须在代码中找到你没有正确关闭连接的地方

您可以通过设置较低的maxLifetime 来减少泄漏,以便更快地将连接返回到池

此属性控制池中连接的最大生命周期。使用中的连接永远不会被淘汰,只有当它关闭时才会被删除。在逐个连接的基础上,应用较小的负衰减以避免池中的大规模灭绝。我们强烈建议设置此值,它应该比任何数据库或基础设施强加的连接时间限制短几秒钟。值 0 表示没有最大生命周期(无限生命周期),当然取决于 idleTimeout 设置。允许的最小值为 30000 毫秒(30 秒)。默认值:1800000(30 分钟)

按照 Hikari 的 PostgreSQL 配置提示 您可以添加监控工具/代码,但您必须解决问题

【讨论】:

以上是关于HikariCP:为啥连接泄漏和释放导致新数据库连接的“连接尝试超时”?的主要内容,如果未能解决你的问题,请参考以下文章

HikariCP 未释放活动的 MySql 连接

为啥“Quarkus”选择“Agroal”而不是“HikariCP”作为首选数据源和连接池实现? [关闭]

为啥使用“新”会导致内存泄漏?

为啥 Netty ByteBuf.readBytes 会导致内存泄漏?

HikariCP

HikariCP 源码分析之 leakDetectionThreshold 及实战解决 Spark/Scala 连接池泄漏