“应用突然连不上数据库了!”——这是运维最怕听到的报警之一。紧接着,监控图上数据库连接数直线飙升,直到打满上限,新的连接请求全部被拒绝。业务瞬间中断,用户端开始报错。
这就是经典的数据库连接池耗尽故障。不管你是Java的HikariCP、Tomcat JDBC,还是Go、PHP的连接池,一旦并发请求超过连接池上限,或者连接未正确释放,就会触发这场“雪崩”。
别慌。下面这三个命令,能在第一时间帮你把业务抢救回来。
第1个命令:看看当前到底有多少连接
SHOW PROCESSLIST;
或者更直观地统计连接状态:
SELECT command, COUNT(*)
FROM information_schema.processlist
GROUP BY command;
作用:快速了解当前连接都在干什么。Command列显示Sleep表示空闲连接,Query表示正在执行的SQL,Locked(MySQL 5.x)表示被锁阻塞。
应急判断:如果发现大量Sleep连接,说明连接池里的连接没有被及时回收——这是最常见的“连接泄漏”。
第2个命令:杀掉“占着茅坑不拉屎”的空闲连接
-- 查询所有空闲超过60秒的连接ID
SELECT id, user, host, db, time
FROM information_schema.processlist
WHERE command = 'Sleep' AND time > 60;
-- 批量杀掉它们(需要拼出kill语句)
SELECT CONCAT('KILL ', id, ';')
FROM information_schema.processlist
WHERE command = 'Sleep' AND time > 60;
把上面生成的KILL xxxx;语句复制出来执行。注意:只杀空闲连接,不要杀正在执行重要事务的Query连接。
作用:瞬间释放被“占着不放”的连接,让新请求能够进来。这是最立竿见影的止血手段。
第3个命令:临时调高连接数上限(紧急扩容)
如果杀掉空闲连接后,连接数依然逼近上限,说明业务真的需要更多连接。
先看当前最大连接数:
SHOW VARIABLES LIKE 'max_connections';
再看当前实际连接数:
SHOW STATUS LIKE 'Threads_connected';
如果Threads_connected已经接近max_connections,可以临时调高(不需要重启数据库):
SET GLOBAL max_connections = 500; -- 根据服务器内存调整
注意:调高max_connections会消耗更多内存。MySQL每个连接大约占用2-4MB内存,500连接就是1-2GB。确保服务器内存有余量,否则调高后可能触发OOM。
以上三个命令能“救急”,但真正的解决要靠“治本”
执行完这三个命令,业务应该能恢复访问。但如果不找到根因,故障还会再次发生。常见的根本原因有四种:
1.代码未关闭连接:例如JDBC的finally块里漏掉了connection.close()。
2.连接池配置太小:峰值并发超过maximumPoolSize。
3.慢SQL阻塞连接:一条慢SQL跑了30秒,把连接长期占用。
4.数据库本身性能瓶颈:CPU/IO过高导致请求排队,连接数随之堆积。
要彻底解决,需要配合慢查询日志分析、APM工具追踪代码路径、以及压测验证连接池参数。
如何避免下一次“连接池爆炸”?
除了掌握应急命令,更建议从日常运维层面做好三件事:
- 监控与告警:对数据库连接数、活跃连接数、空闲连接数设置阈值告警,比如“活跃连接数超过最大连接数的80%”时提前预警。
- 自动化应急:在监控平台中配置自动化响应规则——检测到连接数超过阈值且空闲连接占比过高时,自动执行Kill空闲连接的脚本;若仍然不足,自动调高max_connections(前提是内存有余量并设置上限)。
- 定期巡检:每周分析慢查询日志,找出长时间运行的SQL并优化;检查连接池参数配置是否匹配实际业务峰值。
对于没有专职DBA的中小团队,除了利用云数据库自带的自治功能,也可以关注一些专业的运维服务商。例如江苏立维,他们在数据库运维方面积累了不少实战经验,会帮助客户预先配置好连接池监控告警与自动化响应逻辑,让这类“半夜连接池爆炸”的问题能在几分钟内自动止血。了解这些成熟的方案,有助于我们更从容地应对突发故障。