异常现象:2001个幽灵连接,max_connections早爆了
MySQL官方文档明确说明:ERROR 1040(HY000):Too many connections触发条件是当前连接数超过max_connections参数值。
我们当时的监控数据很明确。
SHOW GLOBAL STATUS LIKE'Threads_connected';显示2001。
SHOW VARIABLES LIKE'max_connections';确认是2000。
应用日志每秒500+条1040错误。架构背景:SpringBoot 2.7+HikariCP 4.0+MySQL 8.0.32,主从架构,18个应用实例,每个实例理论最大连接100个,总容量应该绰绰有余。
但现实是,Sleep连接占总数的82%,这就是幽灵军团。配置合理≠实际稳定,监控数据才是真相。 秒级自救:借管理端口起死回生MySQL8.0.14及以上版本增加了admin_address以及admin_port,默认是33062这个端口,和平常的3306端口完全分开。
这种设计就是,用来让DBA在紧急时候使用,能够避开连接数的限制。完整自救步骤(实测28秒)
-
创建临时管理员(权限最小化)
sqlCREATE USER 'tmp_admin'@'%' IDENTIFIED BY 'Tmp2025!Secure'; GRANT PROCESS, SUPER, REPLICATION CLIENT ON *.* TO 'tmp_admin'@'%';FLUSH PRIVILEGES; -
管理端口登入
cssmysql -u tmp_admin -p -h 127.0.0.1 --port=33062 --connect-timeout=5 -
验证成功:此时SHOW_PROCESSLIST;能看到所有2001个连接,包括Sleep的。
-
数据验证:登录后立即执行SELECT COUNT(*) FROM information_schema.PROCESSLIST WHERE COMMAND='Sleep';确认1640个Sleep连接。
太绝了,8.0的管理端口救了我7次夜间故障。 根因定位:80%的连接在睡眠,sys视图一目了然sys.user_summary_by_statement_type是MySQL8.0sys模式的神器,按语句类型汇总用户连接统计。执行结果(真实截图数据)
| statementtype | count | ratio |
|---|---|---|
| sleep | 1640 | 82% |
| Query | 280 | 14% |
| Connect | 81 | 4% |
继续深挖。
sql
SELECT * FROM sys.processlistWHERE state='Sleep' AND time > 300ORDER BY time DESC LIMIT 10;
发现82%的Sleep连接存活超过5分钟,明显是泄漏。80%Sleep连接=连接池配置失控,数据不会说谎。 真正的元凶:maxIdle时间过长+无泄漏检测HikariCP官方推荐:maxLifetime应小于MySQLwait_timeout(默认28800s=8小时),idleTimeout建议5-10分钟。我们之前的配置是灾难。
yaml
hikari:
maximum-pool-size: 100 # 峰值 OK
minimum-idle: 20 # 偏高
max-lifetime: 30m # ❌ 过长!
idle-timeout: 10m # ❌ 回收太慢
leak-detection-threshold: 0 # ❌ 关闭检测!
行业数据对比(阿里云最佳实践)
- 合理maxIdle:20-50(视QPS)
- leakDetectionThreshold:3000-10000ms
我们的QPS峰值800,18实例,理论需45个活跃连接即可。
代码隐患:3处JDBC操作缺少try-with-resources,异常路径未释放连接。配置不是越多越好,是越精准越安全。 修复方案:池子瘦身+死信检测双保险上线后出现这种状况,连接数从2001降至峰值58,随后逐步回落至25至35的区间,稳定性提高了16倍。核心改动
makefile
spring:
datasource:
hikari:
maximum-pool-size: 80 # ↓20%,匹配实际峰值
minimum-idle: 10 # ↓50%
max-lifetime: 5m # 5分钟强制刷新
idle-timeout: 300000 # 5分钟回收空闲
leak-detection-threshold: 5000 # 5秒告警
leakDetectionThreshold原理:连接checkout后超过阈值未return,打印stacktrace定位泄漏代码。修复后日志Connection leak detection triggered for example.com.example.MyService#queryUser,stack trace follows3处代码立即修复,故障率下降94%。预防之道:MySQL8.0.28+连接内存限制MySQL8.0.28新特性:connection_memory_limit,默认每个连接1MB,可设16MB。
超限自动KILL。配置
ini
SET PERSIST connection_memory_limit = 16777216; # 16MBSET PERSIST connection_memory_chunk_limit = 1048576; # 1MB 递增
实际效果数据
- 前:单连接峰值内存28MB
- 后:强制杀掉超限连接,OOM风险降为0
- 监控:SHOW STATUS LIKE 'Aborted_clients';增加但可控
结合对连接池进行优化,系统的容量提升了3倍,单个实例支持1200QPS。8.0的内存限流=最后的防线,一个参数挡住OOM雪崩。 总结与展望凌晨两点的那次事件,成了团队数据库管理的宝贵经验,从以往的被动应对转为主动监控,我们依靠数据做决策,通过优化配置来保障系统稳定。现在标准流程是:
- 连接池参数按QPS计算:maxPoolSize=QPS*1.5连接复用率(0.8)
- 强制开启leakDetectionThreshold=5s
- MySQL8.0+开启connection_memory_limit=16M
- 每周跑sys视图体检
上线90天,类似故障0次,客户满意度回升22%。
技术人的成长,就是从一次次血亏中爬起来。 碰到连接方面的问题的时候,不要着急,先试着操作管理端口,随后查看sys视图,最后调整连接池,你分享的实践经验,是我持续深入钻研技术的最优动力。
声明,此文章里90%是我本人原创,有极少部分素材由AI帮助生成,而且所有内容我都已经认真核查,图片素材要么是真实的要么是AI原创的,此文章旨在传播正能量,不存在低俗不好的引导,期望读者可以理解。