跳转到内容

保活、驱逐与故障检测

HikariCP 不把所有连接检查都塞进借出线程,而是把时间驱动的维护拆给 HouseKeeper 和每条连接的定时任务;借出路径只处理已经暴露的失效条目。

先给答案:HikariCP 不把所有连接检查都塞进借出线程,而是把时间驱动的维护拆给 HouseKeeper 和每条…

Section titled “先给答案:HikariCP 不把所有连接检查都塞进借出线程,而是把时间驱动的维护拆给 HouseKeeper 和每条…”

HikariCP 不把所有连接检查都塞进借出线程,而是把时间驱动的维护拆给 HouseKeeper 和每条连接的定时任务;借出路径只处理已经暴露的失效条目。 正文沿“HouseKeeper -> 生命周期和保活 -> Soft eviction”展开:先确认入口和状态归属,再跟踪控制流或数据流的推进,最后落到对外可观察的结果。

主要失效边界集中在“maxLifetime 太短、keepalive 太密、时钟跳变”这些场景。它们破坏的是容量、顺序、并发或生命周期前提;排查时应先确认状态是否仍由正确对象持有,再核对推进条件和清理路径。

  • HouseKeeper:src/main/java/com/zaxxer/hikari/pool/HikariPool.java:793-842。
  • 周期任务调度::118。
  • 软驱逐全部连接::820。
  • idleTimeout 清理::834-836。
  • 连接补充判断::528-533。
  • createPoolEntry 设置 maxLifetime:HikariPool.java:485-498。
  • keepalive 周期与随机偏移::498-503。
  • MaxLifetimeTask::855-868。
  • KeepaliveTask::870-889。
  • 失效连接 soft evict::883。
  • softEvictConnection::614-630。
  • PoolEntry#close 取消任务:PoolEntry.java:175-190。

软驱逐先把条目标记为不可继续使用;如果连接空闲,可以立即保留并关闭,如果连接正在使用,则等代理归还时由 owner 路径完成关闭。这避免强行中断业务线程持有的 JDBC 连接。

为什么使用随机化 maxLifetime/keepalive

Section titled “为什么使用随机化 maxLifetime/keepalive”

替代方案:所有连接严格在同一时间到达 maxLifetime 并同时重连。 为什么不行:批量过期会形成连接重建尖峰,给数据库和网络造成周期性压力。 证据:HikariPool.java:498-503 为 keepalive 引入 keepaliveTime / 5 的随机偏移;maxLifetime 任务通过独立调度错开生命周期。

场景 现象 原因 规避
maxLifetime 太短 连接频繁重建 小于数据库稳定连接周期 结合数据库 wait_timeout 配置
keepalive 太密 空闲连接持续被探测 网络/数据库负载增加 只在确有中间设备断连时启用
时钟跳变 HouseKeeper 触发异常清理 系统时间不稳定 使用稳定时钟并监控 NTP
使用中驱逐 当前请求不立即失败 soft eviction 等待归还 理解“标记后关闭”语义

后台维护应与业务线程解耦,但不能粗暴强杀正在使用的资源。软驱逐、延迟关闭和随机化调度是连接池、缓存和租约系统都能复用的可靠性模式。

面试锚点

  • maxLifetime 和 idleTimeout 的区别是什么?
  • 为什么驱逐连接要采用 soft eviction?
  • keepalive 为什么需要随机偏移?