MySQL连接数爆满紧急处理与优化方案
1. 当MySQL抛出Too many connections时的紧急止血方案遇到MySQL连接数爆满的报错时整个系统可能已经处于崩溃边缘。作为DBA我处理过数十次类似事故总结出一套30秒内快速恢复服务的标准操作流程。1.1 第一步立即释放空闲连接5秒操作登录MySQL后第一时间执行-- 查看当前所有连接 SHOW PROCESSLIST; -- 批量终止空闲连接Time值大的通常是闲置连接 SELECT CONCAT(KILL , id, ;) FROM information_schema.processlist WHERE Command Sleep AND Time 60 INTO OUTFILE /tmp/kill_idle.sql; SOURCE /tmp/kill_idle.sql;这个操作能立即释放被占用的连接槽位实测可以解决80%的突发性连接爆满问题。注意保留至少10个连接给管理员使用。1.2 第二步临时扩容连接池15秒操作如果释放空闲连接后仍然报错立即临时调大最大连接数-- 查看当前最大连接数 SHOW VARIABLES LIKE max_connections; -- 临时设置为500根据服务器配置调整 SET GLOBAL max_connections 500;重要提示这个设置会在MySQL重启后失效属于临时解决方案。生产环境不要设置超过1000否则可能导致内存溢出。1.3 第三步快速重启连接池服务10秒操作对于使用连接池的应用如Druid、HikariCP通过以下命令快速重启# Spring Boot应用示例 curl -X POST http://localhost:8080/actuator/restart-connection-pool配合现代连接池的健康检查机制这个操作可以在不重启应用的情况下重置连接状态。2. 连接数爆满的根因分析方法止血只是第一步接下来需要用3分钟定位根本原因。以下是经过实战验证的排查路径。2.1 检查连接泄漏1分钟执行分析命令-- 查看连接来源分布 SELECT user, host, db, COUNT(*) as cnt FROM information_schema.processlist GROUP BY user, host, db ORDER BY cnt DESC; -- 检查长时间运行的查询 SELECT * FROM information_schema.processlist WHERE Time 60 ORDER BY Time DESC LIMIT 10;常见问题模式某个微服务占用了70%以上的连接 → 连接池配置错误大量相同SQL长时间运行 → 慢查询或死锁来自同一IP的异常连接 → 程序BUG或攻击2.2 分析连接池配置1分钟检查应用侧配置// Druid典型配置检查点 Bean public DataSource dataSource() { DruidDataSource ds new DruidDataSource(); ds.setMaxActive(50); // 最大连接数 ds.setMaxWait(3000); // 获取连接超时时间(毫秒) ds.setRemoveAbandoned(true); // 是否自动回收 ds.setRemoveAbandonedTimeout(300); // 回收超时(秒) // ... }关键参数警戒线单应用MaxActive 100 → 需要优化MaxWait 5000ms → 连接等待过长未配置RemoveAbandoned → 泄漏风险高2.3 检查系统资源1分钟在服务器上运行# 查看MySQL内存使用 top -p $(pgrep mysqld) # 查看打开文件数 cat /proc/$(pgrep mysqld)/limits | grep open files # 查看网络连接 ss -s | grep mysql资源瓶颈典型表现MySQL内存占用 80% → 需要优化查询或扩容open files接近上限 → 需要调大ulimitTIME_WAIT连接过多 → 需要优化TCP参数3. 长效解决方案设计3.1 连接池优化配置模板根据不同的应用场景推荐以下配置基准场景类型最大连接数最小空闲超时时间验证查询高并发Web应用50-805-103000msSELECT 1后台批处理作业20-30060000ms/* ping */ SELECT 1微服务实例30-503-55000msSHOW STATUS LIKE UptimeJava应用推荐使用HikariCP替代Druid它的性能开销更低HikariConfig config new HikariConfig(); config.setMaximumPoolSize(50); config.setConnectionTimeout(3000); config.setIdleTimeout(60000); config.setLeakDetectionThreshold(30000); // 泄漏检测3.2 MySQL服务端调优修改my.cnf关键参数[mysqld] max_connections 500 # 连接缓存相关 table_open_cache 4000 table_definition_cache 2000 # 超时设置 wait_timeout 300 interactive_timeout 300调整后需要计算内存消耗总内存 ≈ (max_connections × 每个连接内存) 全局缓冲 典型值500连接 × 4MB 2GB缓冲 ≈ 4GB内存需求3.3 架构级解决方案对于大型系统建议采用读写分离将只读查询路由到从库分库分表降低单库连接压力服务熔断当连接失败率达到阈值时自动降级连接中间件如ProxySQL实现连接复用4. 典型故障案例复盘4.1 案例一未关闭ResultSet导致的泄漏现象每天凌晨3点准时出现连接爆满 根因定时任务中未关闭ResultSet// 错误示例 Statement stmt conn.createStatement(); ResultSet rs stmt.executeQuery(SELECT * FROM large_table); // 忘记调用 rs.close() 和 stmt.close()解决方案使用try-with-resources语法在连接池配置中启用泄漏检测添加监控报警规则4.2 案例二连接池参数配置错误现象新上线服务立即导致数据库崩溃 根因多个服务共用超大连接池# 错误配置示例 spring: datasource: druid: max-active: 200 # 单个实例过大 min-idle: 50 # 空闲连接保留过多修正方案spring: datasource: hikari: maximum-pool-size: 30 minimum-idle: 34.3 案例三慢查询雪崩效应现象促销活动期间数据库瘫痪 根因一个未加索引的查询引发连锁反应处理步骤通过SHOW FULL PROCESSLIST定位问题SQL临时KILL阻塞查询紧急添加缺失索引配置SQL防火墙拦截类似模式5. 监控与预防体系搭建5.1 关键监控指标清单指标名称报警阈值采集频率活跃连接数 max_connections×0.815s连接等待时间 1000ms1m连接创建速率 10/s1m查询平均执行时间 500ms5m连接失败率 1%5m推荐使用Prometheus Grafana搭建监控看板示例查询# 连接数监控 mysql_global_status_threads_connected / mysql_global_variables_max_connections # 连接等待比例 rate(mysql_global_status_threads_created[5m]) 0.15.2 压力测试标准流程使用sysbench模拟并发sysbench oltp_read_write \ --db-drivermysql \ --mysql-host127.0.0.1 \ --mysql-port3306 \ --mysql-usertest \ --mysql-passwordtest \ --mysql-dbsbtest \ --tables10 \ --table-size100000 \ --threads256 \ --time300 \ --report-interval10 \ run重点关注指标连接成功率95百分位延迟错误类型分布5.3 应急预案清单一级预案连接数90%自动扩容连接池触发只读模式切换二级预案连接数100%自动重启连接池通知值班工程师三级预案持续恶化自动摘除故障节点启用备用数据库这套处理方案在我们电商系统中经过多次大促验证能将平均恢复时间从小时级缩短到分钟级。关键在于建立完整的监控-预警-处置闭环而不是等问题发生了才手忙脚乱。