
HikariCP 连接池参数我照着线上监控调了一遍最小空闲、最大池、泄漏检测连接池参数这玩意默认值能跑但一到高峰期就现原形。我们的招聘系统被 DBA 找过两次一次是连接池打满接口报Connection is not available, request timed out after 30000ms一次是池子空转占着数据库不放。这篇把我按监控调参的过程记下来参数和判断方法都能直接抄。先看默认参数和我的第一版配置Spring Boot 3 默认用 HikariCPmaximumPoolSize10这数值对单机接口够呛。我的第一版配置spring:datasource:hikari:minimum-idle:5# 最小空闲连接maximum-pool-size:20# 最大连接数connection-timeout:30000# 拿连接超时idle-timeout:600000# 空闲 10 分钟回收max-lifetime:1800000# 连接最长存活 30 分钟pool-name:qkl-main-pool20 个连接看着够结果双十一活动那天照样打满。踩坑一maxPoolSize 不是越大越好20 → 35 反而 P99 变高现象压测 200 并发maximum-pool-size从 20 调到 35本以为吞吐上去结果接口 P99 从 180ms 涨到 420ms数据库 CPU 从 40% 飙到 75%。排查先看慢日志没有新增慢 SQL再看show processlist发现大量Sleep状态的连接挂着实际执行查询的不到 10 个。用命令确认SHOWVARIABLESLIKEmax_connections;-- 库本身 151SELECTCOUNT(*)FROMinformation_schema.processlistWHEREcommandSleep;-- 挂起一堆定位我们单库 4 核 CPU35 个连接远超CPU核数 × 2 1 9的经验值。连接多不代表快并发查询排队都在 CPU 上连接数超过 CPU 核数后只会增加上下文切换。而且 HikariCP 的连接是懒创建池子大反而让每个查询都在抢连接。解决改回maximum-pool-size: 154 核 × 2 1 ≈ 9~15配合minimum-idle: 8压测 P99 回到 190msCPU 降到 45%。结论连接数要和数据库 CPU 核数挂钩不是拍脑袋调大。踩坑二连接泄漏池子被耗尽报错像网络问题现象凌晨告警某接口偶发Connection is not available, request timed out after 30000ms看着像数据库挂了但 DBA 说库很健康。排查抓线程栈发现大量线程卡在getConnection上jstack|grep-A10HikariPool-1再配合 HikariCP 的泄漏检测关键spring:datasource:hikari:leak-detection-threshold:6000# 连接借出超过 6 秒就报警定位日志里打出Connection leak detection triggeredAPPARENT DEADLOCK字样顺藤摸瓜找到ExcelServicetry 里开了connection.prepareStatement批量插入finally 只关了rs和stmt漏关了connection本身。解决改成 try-with-resources 保底确保每个Connection都归还try(ConnectionconndataSource.getConnection();PreparedStatementpsconn.prepareStatement(insertSql)){ps.setString(1,dto.getName());// ...ps.executeBatch();}// 自动关闭,连接归还池子上线后一周没有再报超时泄漏检测阈值也保留着以后谁再漏关连接日志直接指认。连接池指标要盯着看别等爆了才去查调参不能靠感觉得让数字说话。Spring Boot 用 actuator micrometer 把 HikariCP 指标暴露出来我盯的是三个management:endpoints:web:exposure:include:health,metricsmetrics:export:simple:enabled:true指标里最有用的是这几个hikaricp.connections.active当前借出的连接数长期贴满 max 就是池子不够或泄漏。hikaricp.connections.pending等待拿连接的线程数pending 持续大于 0 说明连接不够用。hikaricp.connections.idle空闲连接数长期为 0 且 active 很高同上。我在 Grafana 里给 active 和 pending 配了告警pending 连续 30 秒 0 就报警。调参之前先看一周曲线池子参数要跟着峰值走不是跟着默认值走。冷启动的坑刚重启完第一次请求特别慢现象发版重启后前十几个请求 P99 飙到 2 秒跑几分钟才恢复正常。排查hikaricp.connections.idle曲线显示重启后 idle 是 0连接全是请求来了现建的。定位HikariCP 的 minimum-idle 是懒填充的启动时只建初始连接不是立刻补满流量一上来连接要一个个现建第一次肯定慢。解决加个启动预热让池子先按 minimum-idle 建好ComponentpublicclassDataSourceWarmerimplementsApplicationRunner{Overridepublicvoidrun(ApplicationArgumentsargs){try{ConnectioncdataSource.getConnection();c.createStatement().execute(SELECT 1);c.close();// 归还池子,触发后续连接按 minimum-idle 填充}catch(SQLExceptionignored){}}}配合把minimum-idle提到和峰值需要的连接数接近重启后第一次请求就是热的P99 直接回到正常水位。慢 SQL 和池子参数的关系别各调各的有次调参效果不明显后来发现根本不是池子的锅一条接口里的 SQL 没走索引单查就要 800ms连接被占着不放池子自然紧张。连接池参数优化前先确认没有慢 SQL 在占池子。排查顺序我固定了-- 1. 先看有没有慢 SQL 在跑SHOWFULLPROCESSLIST;-- 2. 看执行计划,确认走没走索引EXPLAINSELECTidFROMwork_orderWHEREstatus1ANDcity赣州ORDERBYcreate_timeDESCLIMIT20;-- 3. 看连接分布SELECTcommand,COUNT(*)FROMinformation_schema.processlistGROUPBYcommand;慢 SQL 清掉同样的池子参数接口 P99 直接砍半。池子参数是放大器不是解药——SQL 本身慢池子调再大也是把慢连接堆在一起先治 SQL 再调池子这个顺序别反。可直接复用的清单maximum-pool-size按数据库 CPU 核数 × 2 1 起步压测后再微调别盲目加大。leak-detection-threshold: 6000必开泄漏检测是定位池子被吃光最快的抓手。数据库连接一律 try-with-resources 或 finally 关闭漏关 Connection 是最隐蔽的泄漏源。盯hikaricp.connections.active/pending/idle三个指标pending 持续 0 就该扩容或查泄漏。出问题先show processlist看 Sleep 连接数区分池子不够和连接泄漏。max-lifetime必须小于数据库wait_timeout否则会被库端杀掉导致连接重建风暴。重启后加个连接预热避免冷启动时第一个请求现建连接。项目源码https://gitee.com/gzqkl/qkl-boot