1. 问题现象与初步排查那天早上刚到公司就收到监控系统的一连串报警——MySQL数据库响应时间飙升部分业务接口开始超时。登录服务器一看好家伙连接数直接飙到了max_connections上限默认151新的连接请求全部被拒绝。这种场景下DBA的血压和数据库的QPS通常会同步上涨。我立即用show processlist命令查看当前连接情况发现大量连接处于Sleep状态且来源IP高度集中。这里有个实用技巧通过host字段过滤可以快速定位问题应用SELECT user, host, db, command, time, state, info FROM information_schema.processlist WHERE host LIKE %10.100.20.% ORDER BY time DESC;果然发现某个微服务节点建立了异常多的空闲连接最长的已经保持连接超过6小时。这显然不符合常理——正常连接池应该在事务完成后及时释放连接。2. 连接泄漏的深度追踪2.1 连接池配置检查首先排查应用端的连接池配置。这个系统使用的是Druid连接池检查配置发现# 错误示范 spring.datasource.druid.max-active50 spring.datasource.druid.min-idle50 spring.datasource.druid.test-on-borrowfalse spring.datasource.druid.test-while-idlefalse这里埋了两个坑将min-idle设置与max-active相同导致连接池始终保持满载状态没有开启空闲连接检测无法自动回收失效连接重要提示生产环境务必配置test-while-idle和timeBetweenEvictionRunsMillis参数建议值spring.datasource.druid.test-while-idletrue spring.datasource.druid.time-between-eviction-runs-millis600002.2 事务代码审计接着检查相关服务的DAO层代码发现典型的连接泄漏模式// 反例没有Transactional注解却手动控制事务 public void updateOrder(Long orderId) { Connection conn dataSource.getConnection(); // 连接泄漏点 try { conn.setAutoCommit(false); // 业务逻辑... conn.commit(); } catch (Exception e) { conn.rollback(); } // 忘记conn.close()! }这种裸用Connection的写法在异常发生时极易导致连接泄漏。更可怕的是这段代码被放在一个循环中调用每次迭代都泄漏一个连接。3. 应急处理与根治方案3.1 临时扩容与连接回收紧急情况下可以临时调整max_connections需重启SET GLOBAL max_connections 500;同时用以下命令强制回收长时间空闲连接注意会影响业务-- 杀死超过10分钟的空闲连接 SELECT concat(KILL , id, ;) FROM information_schema.processlist WHERE command Sleep AND time 600 INTO OUTFILE /tmp/kill.sql; SOURCE /tmp/kill.sql;3.2 连接池最佳实践长期解决方案需要多管齐下标准化配置模板# Druid推荐生产配置 spring.datasource.druid.max-active20 spring.datasource.druid.min-idle5 spring.datasource.druid.initial-size5 spring.datasource.druid.test-while-idletrue spring.datasource.druid.time-between-eviction-runs-millis60000 spring.datasource.druid.min-evictable-idle-time-millis300000统一事务管理禁止手动获取Connection实例强制使用Transactional注解配置事务超时时间Transactional(timeout 30)监控体系建设-- 监控连接数趋势 SHOW GLOBAL STATUS LIKE Threads_connected; -- 计算连接利用率 SELECT (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME Threads_connected) / (SELECT VARIABLE_VALUE FROM performance_schema.global_variables WHERE VARIABLE_NAME max_connections) * 100 AS connection_usage_rate;4. 深度防御机制4.1 连接泄漏检测在测试环境启用Druid的泄漏检测spring.datasource.druid.remove-abandonedtrue spring.datasource.druid.remove-abandoned-timeout300 spring.datasource.druid.log-abandonedtrue4.2 连接池选型对比特性DruidHikariCPTomcat JDBC性能中等极高中等监控功能完善基础有限泄漏检测支持不支持部分支持适合场景需要监控的场景极致性能需求简单应用4.3 连接数计算公式合理的max_connections值应该满足max_connections (应用实例数 × 每个实例连接池大小) 管理预留例如10个应用实例每个实例max-active20管理连接预留20 则10×20 20 2205. 典型问题排查指南问题现象1连接数缓慢增长直至爆满检查方向连接泄漏、未关闭ResultSet/Statement问题现象2连接数瞬间飙升检查方向连接池配置过小、突发流量、循环创建连接问题现象3大量Login状态连接检查方向认证失败、网络抖动、连接串错误实用诊断命令# 实时监控连接数变化 watch -n 1 mysqladmin -uroot -p ext | grep Threads # 分析连接来源 mysql SELECT host, COUNT(*) FROM information_schema.processlist GROUP BY host;这次事故给我的深刻教训是数据库连接就像会议室资源必须谁申请谁释放用完即走。我们现在将连接池监控纳入了Grafana大盘设置了三级预警阈值70%/85%/95%再配合CI/CD中的SQL静态检查基本杜绝了类似问题。