一、事故现场
下午3点,运维监控大屏突然变红。
[严重告警] MySQL CPU使用率:60%
[严重告警] MySQL CPU使用率:280%
[紧急告警] MySQL CPU使用率:680%
从60%到680%,只用了5-10分钟。业务系统开始出现明显卡顿。
• 用户反馈:页面加载变慢,点击无响应
• 运维反馈:数据库连接堆积,慢SQL告警不断
• 应用日志:大量超时错误,线程池打满
图1:MySQL CPU飙升趋势(60% → 680%,约10分钟)
二、排查思路:先止血,再定位根因
这次CPU飙升和普通的慢查询不一样——增长速度太快,而且越往后越卡。直觉告诉我,这不是单一慢查询的问题。
排查原则:先止血保命,再全面排查,最后聚焦根因。
图2:MySQL CPU飙升排查流程图
2.1 第一步:止血——确认影响范围
① 确认业务影响
先判断是全部业务受影响还是部分接口:
查看当前连接数
mysql -e "SHOW STATUS LIKE 'Threads_connected';"
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| Threads_connected | 487 | <-- 正常值应该在50-100左右
+-----------------+-------+
② 查看是否有大量慢查询
查看慢查询数量
mysql -e "SHOW GLOBAL STATUS LIKE 'Slow_queries';"
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Slow_queries | 1247 | <-- 异常偏高
+---------------+-------+
图3:慢SQL堆积趋势(系统越来越卡)
2.2 第二步:系统层排查
系统层资源充足,CPU飙升是MySQL自身造成的。
2.3 第三步:MySQL层深度排查
① 查看当前所有连接
mysql -e "SHOW PROCESSLIST\G"
图4:SHOW PROCESSLIST输出(大量长时间运行查询)
发现异常:
多个查询运行时间超过30分钟,而且State显示各种锁等待。
② 用AI帮忙分析PROCESSLIST
PROCESSLIST有几百行,人工看太费劲。让AI帮忙分析:
【当前症状】
-
MySQL CPU从60%飙升到680%,5-10分钟内
-
Threads_connected: 487(正常50-100)
-
Slow_queries: 1247
-
多个查询Time超过1800秒,状态为Locked/metadata lock
【请分析】
-
这些长时间运行的查询,最可能的原因是什么?
-
"Locked" 和 "Waiting for table metadata lock" 是什么关系?
-
CPU飙升和这些锁等待有什么关联?
③ 查看InnoDB状态
mysql -e "SHOW ENGINE INNODB STATUS\G"
关注以下关键信息:
2.4 第四步:抽丝剥茧——定位根因
图5:根因链条——大查询被KILL后的雪崩效应
经过完整的排查,根因链条清晰了:
① 最初的触发点:大查询被KILL但进程未退出
-- 查看是否有过被KILL的查询
SELECT * FROM information_schema.INNODB_TRX WHERE TRX_STATE = 'RUNNING';
-- 查看事务运行时间
SELECT id, time, state, info FROM information_schema.PROCESSLIST WHERE time > 300;
发现:有一个查询运行超过1小时(Time=3600+),这个查询在之前被手动KILL了,但进程清理未完成。
② 连锁反应:工作流阻塞 + 新请求堆积
大查询被KILL后,清理进程仍在消耗CPU。同时:
• 工作流依赖该查询结果,无法继续执行
• 工作流线程被阻塞在表锁上
• 新的工作流请求不断堆积
• 数据库连接数不断攀升(487个)
③ 雪崩效应:系统越来越卡
① 大查询被KILL,清理进程占用CPU
② 表锁未释放,工作流无法提交
③ 新请求堆积,连接数暴涨
④ 新请求也变成慢查询
⑤ CPU从60% → 280% → 680%
⑥ 系统越来越卡 → 雪崩
三、解决方案:分步处理
① 第一步:KILL僵尸查询
先清理掉那些长时间运行且无意义的查询:
-- 找出运行超过30分钟的查询
SELECT CONCAT('KILL ', id, ';') FROM information_schema.PROCESSLIST
WHERE Command != 'Binlog Dump' AND Time > 1800;
-- 或者直接KILL特定ID
KILL 15234; -- Time=2847秒的查询
KILL 15235; -- Time=2156秒的查询
KILL 15240; -- Time=1890秒的查询
② 第二步:释放表锁
如果KILL后锁仍未释放,需要强制解锁:
-- 查看当前锁状态
SHOW OPEN TABLES WHERE In_use > 0;
-- 查看元数据锁
SELECT * FROM information_schema.INNODB_METRICS WHERE NAME LIKE 'metadata_lock%';
-- 等待锁超时自动释放
SET GLOBAL innodb_lock_wait_timeout = 50; -- 调整为50秒
③ 第三步:扩容临时应对
如果CPU仍然高,可以临时扩容:
在负载均衡层限制流量
或者临时增加MySQL服务器资源
监控CPU下降情况
④ 第四步:索引优化(根因解决)
找到那条运行1小时的查询,分析为什么会这么慢:
-- 查看慢查询日志
SHOW VARIABLES LIKE 'slow_query_log%';
-- 查看执行计划
EXPLAIN SELECT * FROM order_logs WHERE create_time > '2024-01-01' ...;
可能的问题:
四、效果验证
五、预防措施
六、AI辅助排查prompt模板
遇到MySQL CPU飙升时,这个prompt可以直接用:
【事故描述】
MySQL CPU从正常值飙升到XX%,系统变卡/无响应
【已有的排查信息】
-
SHOW PROCESSLIST结果:[粘贴关键行]
-
SHOW ENGINE INNODB STATUS结果:[粘贴关键段落]
-
Threads_connected: XX
-
Slow_queries: XX
【请分析】
-
最可能的3个根因方向
-
长时间运行的查询最可能是什么问题?
-
"Locked"/"metadata lock" 和CPU飙升有什么关系?
-
应该优先KILL哪些查询?
七、经验总结
这次MySQL CPU飙升的特殊之处在于——表面上是要优化慢查询,实际上是一个被KILL的查询引发的连锁反应。
这类问题的排查要点:
• 不要只看慢查询数量,要看PROCESSLIST中Time最长的那些
• 长时间运行的查询即使被KILL,清理过程也可能消耗大量资源
• 表锁/元数据锁会阻塞后续请求,形成雪崩效应
• 监控要关注连接数变化趋势,比CPU告警更早发现问题
排查顺序建议:
① SHOW PROCESSLIST → 找Time最长的查询
② SHOW ENGINE INNODB STATUS → 看锁等待情况
③ information_schema表 → 查事务和锁详情
④ KILL僵尸查询 → 止血
⑤ EXPLAIN慢查询 → 找根因
⑥ 加索引/优化SQL → 治本