HikariCP:为啥连接泄漏和释放导致新数据库连接的“连接尝试超时”? Posted 2023-02-27
技术标签:
【中文标题】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 连接池泄漏