连接池监控与健康检查
连接池调优做了一大堆,性能数据也好看。但有一天线上突然大量超时,你慌不慌?
我告诉你,不慌是假的。调优的成果能不能持续,就看监控和健康检查做没做到位。说白了,连接池是个黑盒子,你不盯着它,它就敢给你搞事情。
这一章,咱们把盖子掀开,看看怎么监控、怎么检查、怎么在连接挂掉之前把它踢出去。
4.1 监控指标
监控不是什么都看,要有重点。我个人的习惯是,先盯死四个核心指标。
| 指标 | 含义 | 计算公式/来源 | 建议阈值 |
|---|---|---|---|
| 活跃连接数 | 当前正在被使用的连接数量 | pool.getActive() | 最大值 < 池大小 × 80% |
| 空闲连接数 | 当前池中未被占用的连接数量 | pool.getIdle() | 最小值 > 核心连接数 × 20% |
| 等待获取连接线程数 | 因池中无可用连接而阻塞的线程数 | pool.getPending() | 接近 0 |
| 连接获取超时次数 | 调用getConnection()超时的累计次数 | pool.getConnectionTimeoutCount() | 0 |
在项目中,我通常会关注前两个指标的变化趋势。如果活跃连接数持续接近池最大值,而等待线程数也开始上涨,就说明池大小不够,或者某个慢查询占着连接不释放。
监控黄金法则:不要只看平均值,要看 P99 和 P999。连接获取时间的 P99 突然从 5ms 飙到 50ms,很可能就是连接泄漏的前兆。
4.2 健康检查策略
你想想看,数据库连接可能因为网络闪断、防火墙超时、数据库重启而变成「死连接」。池里面全是死连接,新的请求进来根本拿不到可用连接。
健康检查就是解决这个问题的。
4.2.1 验证查询
最常见的做法,是在连接归还或借出时,执行一个轻量级的 SQL 查询,确认连接还活着。
# HikariCP 配置示例
spring.datasource.hikari.connection-test-query=SELECT 1
spring.datasource.hikari.connection-timeout=30000
spring.datasource.hikari.validation-timeout=5000
这里要注意,查询越简单越好。SELECT 1 就够了,别搞 SELECT * FROM big_table。我曾经见过有人用 SELECT COUNT(*) FROM users 做验证,结果线上压力大时,验证查询本身就把数据库拖慢了。
4.2.2 空闲连接扫描
连接一直闲置也会被数据库侧断开。HikariCP 默认会每隔 30 秒扫描一次空闲连接,把那些超过 maxLifetime 的连接干掉。
我个人推荐开启 leakDetectionThreshold,这能帮你快速定位忘记归还连接的代码。
spring.datasource.hikari.leak-detection-threshold=60000
如果某个连接被占用了超过 60 秒还没归还,HikariCP 就会打印一条详细的堆栈日志。你在日志里搜一下"Connection leak",就知道哪个位置忘记 close 了。
避坑提醒:我曾经遇到一个项目,把 leakDetectionThreshold 设得太低,比如 5 秒。结果正常的事务(比如导出报表)每次都触发泄漏告警,告警系统直接被冲垮。建议设在实际业务最长事务时间的 1.5 到 2 倍。
4.3 健康检查的实现方式
不同连接池的检查机制略有差异,但核心思路一样。我们以 HikariCP 和 Druid 为例。
| 特性 | HikariCP | Druid |
|---|---|---|
| 验证时机 | 借出时 / 空闲扫描时 | 借出时 / 归还时 / 空闲扫描时 |
| 验证查询 | connectionTestQuery | validationQuery |
| 空闲扫描间隔 | idleTimeout (默认 30 秒) | timeBetweenEvictionRunsMillis |
| 泄漏检测 | leakDetectionThreshold | removeAbandoned + removeAbandonedTimeout |
| 连接回收方式 | 关闭并移除,新建替代 | 可选:关闭并移除 / 重建 |
对于 Druid,我还推荐开启 testWhileIdle 和 testOnReturn。不过要注意,testOnBorrow 会在每次获取连接时都执行验证,对高频调用的场景会造成额外开销。
实践建议:如果业务允许,优先使用空闲扫描 + 懒惰验证。即连接借出时不验证,只有在空闲时间超过一定阈值时才做验证。这样可以大幅降低验证查询对数据库的压力。HikariCP 默认就是这种策略。
4.4 监控集成方案
有了指标和检查,还得把数据收集起来,搭一个看得见的仪表盘。
4.4.1 通过 JMX 暴露指标
HikariCP 自带 JMX 支持,开启后就能通过 JConsole 或 VisualVM 看到池的运行时状态。
4.4.2 通过 Micrometer 上报到 Prometheus
// Spring Boot 中自动绑定 HikariCP 指标到 Micrometer
// 配合 micrometer-registry-prometheus 暴露 /actuator/prometheus 端点
// 关键指标名称:
// hikaricp_connections_active
// hikaricp_connections_idle
// hikaricp_connections_pending
// hikaricp_connections_timeout_total
嗯,这里要注意。Micrometer 默认会把所有池的指标都绑定上去。如果应用里配了多个数据源,指标名会自动带上池名称,丢到 Grafana 里做面板时记得按 pool 字段分组。
4.4.3 自定义健康检查端点
Spring Boot Actuator 的 /actuator/health 已经包含了数据源的健康状态。但默认只检查能不能获取一个连接,不够细。你可以扩展 HealthIndicator 来增加自定义逻辑。
@Component
public class ConnectionPoolHealthIndicator implements HealthIndicator {
@Autowired
private DataSource dataSource;
@Override
public Health health() {
HikariDataSource hds = (HikariDataSource) dataSource;
int active = hds.getHikariPoolMXBean().getActiveConnections();
int idle = hds.getHikariPoolMXBean().getIdleConnections();
int pending = hds.getHikariPoolMXBean().getThreadsAwaitingConnection();
if (pending > 10) {
return Health.down()
.withDetail("active", active)
.withDetail("idle", idle)
.withDetail("pending", pending)
.build();
}
return Health.up()
.withDetail("active", active)
.withDetail("idle", idle)
.build();
}
}
4.5 告警与自动化处理
光有面板还不够,得有告警。我习惯把告警做三层:
- 信息告警:连接池使用率超过 70%,发到钉钉/飞书,让值班人员关注。
- 警告告警:连接获取超时次数 > 5 次/分钟,发短信,要求 10 分钟内响应。
- 严重告警:健康检查连续失败 3 次,直接调用脚本重启连接池或切到备用数据库。
自动化处理部分,我建议不要用连接池的自动恢复功能在线上直接生效。可以在健康检查失败时,先走容灾切换,再告警让运维介入排查原因。自动恢复容易掩盖根本问题,导致故障反复出现。
核心原则:监控和健康检查不是运维的附属品,而是连接池调优的护栏。没有监控,调优就是盲人摸象。