连接池爆满本质是系统性症状,需分层排查:先确认是应用侧连接池满(如hikaricp报connection timeout、active=maximum)、mysql侧打满(show status like 'threads_connected'接近max_connections或报too many connections),还是两者配置失配;再通过show processlist、innodb_trx及代码审计定位慢sql、长事务或连接泄漏;仅在排除根因、qps真实增长且资源余量充足时,才按公式(qps×平均占连时间×1.5)审慎扩容,并同步调优超时与健康检查。

连接池满不是直接调大 maximumPoolSize 就完事,而是要先确认是不是真该扩容——大多数时候,它只是个表象,背后是连接泄漏、SQL慢、事务没关、超时没配对等问题。盲目扩容只会让数据库更卡、内存更高、问题更难定位。
先查清楚“满”到底是哪一层满了
连接池满有多个层级,得一层层看:
-
应用侧连接池满:HikariCP 或 Druid 报
Connection acquisition timeout,监控显示activeConnections持续等于maximumPoolSize,且pendingThreads在涨 -
MySQL 侧连接打满:执行
SHOW STATUS LIKE 'Threads_connected';接近max_connections,或出现Too many connections错误 -
两者不匹配:比如 Java 池设了 200,但 MySQL 的
max_connections=151,那池子还没满,MySQL 先拒绝新连,表现为获取连接失败但池中无等待线程
不是扩容,是先止损和归因
发现爆满后,立刻做三件事:
- 查当前活跃连接:
SHOW PROCESSLIST;看哪些连接长期Sleep或卡在Query,重点关注Time列大于 30 秒的 - 查慢 SQL 和未提交事务:
SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(timediff(now(), trx_started)) > 30; - 检查代码里有没有
try-with-resources缺失、finally忘 close、Stream.forEach 里开了连接没释放等典型泄漏点
确认真要扩容,再按步骤调参
只有当以下条件同时满足,才考虑适度扩容:
- 历史峰值
Max_used_connections稳定在当前max_connections的 85% 以上,且硬件资源(内存、CPU、文件描述符)仍有余量 - 连接池监控显示
idleConnections常为 0,connectionTimeout频繁触发,且平均连接持有时间合理(比如 100–300ms) - 已排除慢 SQL、长事务、连接泄漏等根因,QPS 确实持续增长
扩容建议节奏:
- MySQL
max_connections每次最多 +20%,同步检查open_files_limit和系统ulimit -n是否跟上(建议 ≥ max_connections × 2) - Java 连接池
maximumPoolSize按公式算:QPS × 平均连接占用时间(秒)× 1.5,例如 QPS=300、平均占连 0.15s → 建议值 ≈ 68,取整到 80 - 必须同步调整超时参数:
connectionTimeout ≤ wait_timeout / 3(如 MySQLwait_timeout=300,则 Java 设30000ms),并启用isValid()校验
扩容后必须配验证和兜底
光改数字没用,得让新配置真正生效并可观察:
- 开启连接池健康指标(HikariCP 的
metricRegistry或 Druid 的内置监控页面),重点盯active、idle、pending、usage四个指标趋势 - 设置
idleTimeout(建议 10 分钟)和maxLifetime(建议 30 分钟),防止连接被 MySQL 静默断开后变成僵尸连接 - 上线后跑 15 分钟压测,观察 MySQL
Threads_created是否陡增——如果每秒新建连接数明显上升,说明连接复用率下降,得回查代码或网络稳定性
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











