Appearance
数据库连接数激增(2万连接)紧急排查与处理手册
一、紧急处理(5分钟内必须完成)
1.1 快速评估连接状况
sql
-- 立即执行,了解连接构成
SHOW STATUS LIKE 'Threads_%';
SHOW GLOBAL STATUS LIKE 'Max_used_connections';
SHOW VARIABLES LIKE 'max_connections';
-- 连接类型分布分析
SELECT
COMMAND,
COUNT(*) as 连接数,
ROUND(COUNT(*)/SUM(COUNT(*)) OVER()*100, 2) as 百分比,
AVG(TIME) as 平均时间,
MAX(TIME) as 最长连接
FROM information_schema.PROCESSLIST
GROUP BY COMMAND
ORDER BY COUNT(*) DESC;1.2 紧急止血措施
sql
-- 步骤1:临时降低最大连接数(防止继续增长)
SET GLOBAL max_connections = 5000;
-- 步骤2:缩短连接超时时间
SET GLOBAL wait_timeout = 30; -- 非交互连接30秒超时
SET GLOBAL interactive_timeout = 30; -- 交互连接30秒超时
-- 步骤3:紧急清理批量空闲连接(执行前请确认)
-- 生成清理语句(先查看,确认无误再执行)
SELECT CONCAT('KILL ', ID, ';') as 清理语句
FROM information_schema.PROCESSLIST
WHERE COMMAND = 'Sleep'
AND TIME > 60 -- 空闲超过60秒
AND USER NOT IN ('system user', 'event_scheduler', 'replication')
AND ID != CONNECTION_ID() -- 不清理当前连接
LIMIT 1000; -- 分批执行,每次10001.3 紧急清理脚本(Shell版)
sh
#!/bin/bash
# emergency_clean.sh
MYSQL_USER="your_admin"
MYSQL_PASS="your_password"
MYSQL_HOST="localhost"
PORT="3306"
echo "当前连接数:"
mysql -h$MYSQL_HOST -P$PORT -u$MYSQL_USER -p$MYSQL_PASS -e "SELECT COUNT(*) FROM information_schema.PROCESSLIST;"
echo "开始清理空闲连接(每次1000,共5轮)"
for i in {1..5}
do
echo "第 $i 轮清理"
mysql -h$MYSQL_HOST -P$PORT -u$MYSQL_USER -p$MYSQL_PASS -e "
SELECT CONCAT('KILL ', ID, ';')
FROM information_schema.PROCESSLIST
WHERE COMMAND = 'Sleep'
AND TIME > 60
AND USER NOT IN ('system user', 'event_scheduler')
LIMIT 1000" | grep 'KILL' > /tmp/kill_commands.sql
if [ -s /tmp/kill_commands.sql ]; then
mysql -h$MYSQL_HOST -P$PORT -u$MYSQL_USER -p$MYSQL_PASS < /tmp/kill_commands.sql
echo "已清理一批连接"
sleep 2 # 等待2秒,避免冲击
else
echo "没有需要清理的连接"
break
fi
done
echo "清理后连接数:"
mysql -h$MYSQL_HOST -P$PORT -u$MYSQL_USER -p$MYSQL_PASS -e "SELECT COUNT(*) FROM information_schema.PROCESSLIST;"二、根本原因排查(紧急处理后执行)
2.1 连接来源分析
sql
-- 查看连接数TOP 10的客户端
SELECT
USER,
SUBSTRING_INDEX(HOST, ':', 1) as 客户端IP,
COUNT(*) as 连接数,
SUM(CASE WHEN COMMAND = 'Sleep' THEN 1 ELSE 0 END) as 空闲连接,
SUM(CASE WHEN TIME > 60 THEN 1 ELSE 0 END) as 长连接,
MIN(CONNECT_TIME) as 最早连接时间
FROM information_schema.PROCESSLIST
LEFT JOIN performance_schema.threads ON PROCESSLIST.ID = threads.PROCESSLIST_ID
WHERE USER NOT IN ('system user')
GROUP BY USER, SUBSTRING_INDEX(HOST, ':', 1)
ORDER BY 连接数 DESC
LIMIT 10;
-- 查看应用连接池配置问题
SELECT
USER,
HOST,
DB,
COUNT(*) as 连接数,
GROUP_CONCAT(DISTINCT LEFT(INFO, 50)) as 查询样例
FROM information_schema.PROCESSLIST
WHERE COMMAND = 'Sleep'
GROUP BY USER, HOST, DB
HAVING COUNT(*) > 10
ORDER BY COUNT(*) DESC;2.2 异常连接检测
sql
-- 检查是否有异常IP大量连接
SELECT
SUBSTRING_INDEX(HOST, ':', 1) as 客户端IP,
COUNT(*) as 连接数,
GROUP_CONCAT(DISTINCT USER) as 使用用户
FROM information_schema.PROCESSLIST
GROUP BY SUBSTRING_INDEX(HOST, ':', 1)
HAVING COUNT(*) > 100 -- 单个IP连接数超过100
ORDER BY COUNT(*) DESC;
-- 检查长时间运行的事务/查询
SELECT
p.ID,
p.USER,
p.HOST,
p.DB,
p.TIME,
p.COMMAND,
p.STATE,
LEFT(p.INFO, 100) as 查询语句,
t.trx_started as 事务开始时间,
TIMESTAMPDIFF(SECOND, t.trx_started, NOW()) as 事务持续时间
FROM information_schema.PROCESSLIST p
LEFT JOIN information_schema.INNODB_TRX t ON p.ID = t.trx_mysql_thread_id
WHERE p.TIME > 60
AND p.COMMAND != 'Sleep'
ORDER BY p.TIME DESC
LIMIT 20;2.3 系统资源检查
sql
-- 检查系统资源使用情况
SHOW ENGINE INNODB STATUS; -- 查看InnoDB状态
-- 检查表锁和行锁
SELECT
r.trx_id as 等待事务,
r.trx_mysql_thread_id as 等待线程,
r.trx_query as 等待查询,
b.trx_id as 阻塞事务,
b.trx_mysql_thread_id as 阻塞线程,
b.trx_query as 阻塞查询,
TIMESTAMPDIFF(SECOND, r.trx_wait_started, NOW()) as 等待秒数
FROM information_schema.INNODB_LOCK_WAITS w
INNER JOIN information_schema.INNODB_TRX b ON b.trx_id = w.blocking_trx_id
INNER JOIN information_schema.INNODB_TRX r ON r.trx_id = w.requesting_trx_id;三、应用层排查
3.1 连接池配置检查点
1. HikariCP配置检查:
- maximumPoolSize:是否设置过大(建议50-200)
- minimumIdle:是否设置过高
- connectionTimeout:是否合理(建议30秒)
- idleTimeout:是否设置(建议10分钟)
- maxLifetime:是否设置(建议30分钟)
2. Druid配置检查:
- maxActive:最大连接数
- initialSize:初始连接数
- minIdle:最小空闲连接
- removeAbandoned:是否开启连接泄露检测
- removeAbandonedTimeout:泄露连接超时时间
3. 常见问题:
- 连接未正确关闭(try-with-resources或finally块缺失)
- 连接池配置在多个地方重复设置
- 应用重启但旧连接未清理3.2 连接泄露检测脚本
java
// Java连接泄露检测示例
public class ConnectionLeakDetector {
public static void checkConnectionLeaks(DataSource dataSource) {
if (dataSource instanceof HikariDataSource) {
HikariDataSource hds = (HikariDataSource) dataSource;
System.out.println("活跃连接: " + hds.getHikariPoolMXBean().getActiveConnections());
System.out.println("空闲连接: " + hds.getHikariPoolMXBean().getIdleConnections());
System.out.println("总连接: " + hds.getHikariPoolMXBean().getTotalConnections());
System.out.println("等待连接: " + hds.getHikariPoolMXBean().getThreadsAwaitingConnection());
}
}
}四、预防与优化措施
4.1 MySQL配置优化(my.cnf)
ini
[mysqld]
# 连接相关
max_connections = 1000 # 根据实际需要调整
wait_timeout = 300 # 5分钟
interactive_timeout = 300 # 5分钟
max_connect_errors = 10000
# 性能相关
thread_cache_size = 32 # 线程缓存
table_open_cache = 2000 # 表缓存
table_definition_cache = 1400
# 监控相关
performance_schema = ON
performance_schema_consumer_events_statements_history = ON4.2 监控与告警配置
sql
-- 创建监控视图
CREATE VIEW connection_monitor AS
SELECT
NOW() as 监控时间,
COUNT(*) as 总连接数,
SUM(CASE WHEN COMMAND = 'Sleep' THEN 1 ELSE 0 END) as 空闲连接数,
SUM(CASE WHEN TIME > 300 THEN 1 ELSE 0 END) as 长空闲连接,
SUM(CASE WHEN COMMAND = 'Query' AND TIME > 30 THEN 1 ELSE 0 END) as 慢查询数,
(SELECT VARIABLE_VALUE
FROM performance_schema.global_status
WHERE VARIABLE_NAME = 'Threads_connected') as 已连接线程数
FROM information_schema.PROCESSLIST;
-- 定期检查语句
SELECT * FROM connection_monitor;4.3 自动化清理脚本(crontab定期执行)
sh
#!/bin/bash
# daily_connection_clean.sh
# 每天凌晨3点执行:0 3 * * * /path/to/daily_connection_clean.sh
MYSQL_CMD="mysql -hlocalhost -uroot -p'password'"
# 清理空闲超过1小时的连接
$MYSQL_CMD -e "
SELECT CONCAT('KILL ', ID, ';')
FROM information_schema.PROCESSLIST
WHERE COMMAND = 'Sleep'
AND TIME > 3600
AND USER NOT IN ('system user', 'event_scheduler')
" | grep 'KILL' | $MYSQL_CMD
# 记录日志
echo "$(date): 清理空闲连接完成" >> /var/log/mysql_clean.log五、常见故障场景及处理
场景1:应用连接池泄露
现象:
- 某个应用服务器的连接数持续增长
- 重启应用后恢复正常,但几小时后再次出现
处理:
1. 检查应用代码中的连接关闭逻辑
2. 启用连接池的泄露检测功能
3. 添加连接使用监控场景2:慢查询阻塞
现象:
- 大量连接状态为"Waiting for table lock"或"Sending data"
- CPU或IO使用率异常高
处理:
1. 使用SHOW PROCESSLIST找出慢查询
2. 使用EXPLAIN分析查询执行计划
3. 优化索引或查询语句
4. 考虑读写分离场景3:DDOS攻击或异常访问
现象:
- 大量来自同一IP的连接
- 连接用户名为空或异常
处理:
1. 使用防火墙限制异常IP访问
2. 设置max_connect_errors参数
3. 启用数据库审计日志六、工具推荐
6.1 监控工具
- Percona Monitoring and Management (PMM) - 免费监控工具
- Prometheus + Grafana - 自定义监控
- MySQL Enterprise Monitor - 官方商业版
6.2 分析工具
- pt-query-digest - 慢查询分析
- innotop - 实时监控
- mytop - 类似top的MySQL监控
6.3 连接中间件
- ProxySQL - 连接池和查询路由
- MySQL Router - 官方路由中间件
- MaxScale - MariaDB官方代理
七、检查清单
紧急处理检查项
- [ ] 已临时降低max_connections
- [ ] 已清理大量空闲连接
- [ ] 已检查系统资源使用情况
- [ ] 已识别连接数最多的客户端IP
根本原因检查项
- [ ] 应用连接池配置检查完成
- [ ] 慢查询分析完成
- [ ] 锁等待分析完成
- [ ] 网络和防火墙检查完成
预防措施检查项
- [ ] 监控告警已设置
- [ ] 配置优化已实施
- [ ] 应用代码审查完成
- [ ] 备份和恢复方案已准备
注意:以上操作在生产环境执行前,请务必在测试环境验证! 重要:任何配置修改都要有回滚方案! 安全:确保操作有完整记录和审批流程!

