?今日关键词:CPU 100% 排查、top 命令、vmstat 分析、iostat 磁盘、SHOW PROCESSLIST、慢查询优化、InnoDB 锁、锁竞争排查、连接风暴处理

凌晨收到 CPU 100% 告警,是不是瞬间慌了神?
之前有朋友问:CPU 飙满时,怎样才能准确判断是不是数据库的问题?
说实话,第一次遇到这种状况的人,完全不知所措是很正常的。只知道重启数据库,结果半小时后 CPU 又满负荷了。
今天就详细聊聊,作为 DBA 面对 CPU 100% 该如何系统排查。把整个过程分解为几个关键步骤,每一步都配有对应命令和判断逻辑。
先搞清楚 CPU 在忙什么
CPU 占满并不是终点。us、sy、wa 这三个指标才是真正的突破口。
us(用户态):应用程序在消耗计算资源。us 高,通常意味着 SQL 在执行大量计算或排序操作。
sy(内核态):系统层在忙碌。sy 高,往往代表着连接风暴或锁竞争。
wa(I/O 等待):CPU 在等待磁盘响应。wa 高,说明磁盘已经是瓶颈。
load average:top 命令第一行有三个数值,分别对应 1 分钟、5 分钟和 15 分钟的平均负载。当负载接近或超过 CPU 核数时,表明系统承受着巨大压力。
看完这几个指标,CPU 100% 的根本原因就大致有方向了。
第一步:top 看谁在吃 CPU
top -c
发现 CPU 100% 之后,先查看是哪个进程在占用资源。
如果是 mysqld,说明数据库自身承受压力,需要继续往下排查。
如果是其他进程,比如 Java 应用,CPU 高可能与数据库无关。到这一步就可以转交给开发同事了。
关键看两点:哪个进程在吃 CPU,以及吃了多少。如果 mysqld 独占 80% 以上,基本可以锁定为数据库问题。
第二步:vmstat 看全局趋势
vmstat 1 10
每隔 1 秒采样一次,共 10 次,观察整体趋势。
r 列(运行队列):数值大于 CPU 核数,说明 CPU 已经不够用了。
b 列(阻塞队列):大于 0 表示有进程在等待 I/O。
swap 列的 si、so:非零说明内存不足,正在进行换入换出。
cs 列(上下文切换):如果突然飙升,需要检查连接数和锁的情况。
vmstat 讲究看趋势。单次数值没有意义,连续观察几秒才准确。
第三步:iostat 确认 I/O 瓶颈
iostat -x 1
%util 接近 100%,说明磁盘几乎打满了。
await 远大于 svctm,表明 I/O 已经排队等候。
CPU 100% 有时是假象。wa 高意味着瓶颈在磁盘,CPU 其实在等 I/O。这时候加 CPU 没用,必须解决磁盘问题。
第四步:SHOW PROCESSLIST 查数据库
系统层排查完毕,如果锁定是 mysqld,就该深入数据库内部了。
SHOW FULL PROCESSLIST;
这一步是 DBA 排查的核心。主要看三方面:
连接数:正常范围几十到几百。如果突然飙升到几千,就是连接风暴。连接风暴会触发大量上下文切换,导致 sy 直接飙高。
正在执行的 SQL:State 列显示 Executing 的就是正在运行的 SQL。有没有执行很久的慢查询?
锁等待:State 显示 Lock wait 的表示在等待锁。大量 Lock wait 堆积,CPU 全部耗费在锁管理上了。
连接风暴是 CPU 高的常见原因。应用连接池配置不当,或者故障重试机制存在问题,瞬间涌入几千个连接。
第五步:慢查询找元凶
-- 查看当前执行时间最长的 SQL
SELECT * FROM information_schema.processlist WHERE command != 'Sleep' ORDER BY time DESC LIMIT 10;
也可以直接查看慢查询日志:
tail -100 /var/log/mysql/slow.log
慢查询是 CPU 高的最大元凶。常见情形包括:
全表扫描:没有走索引,几百万行全部扫描一遍。CPU 一直在做行比较。
复杂排序:ORDER BY + GROUP BY 组合,临时表放不下只能写磁盘。CPU 和 I/O 同时飙高。
子查询嵌套:优化器选错了执行计划,嵌套循环执行了上亿次。
重点关注 Rows_examined 字段。如果扫描行数远大于返回行数,说明索引没有正确使用。
补充:InnoDB 状态看锁竞争
SHOW ENGINE INNODB STATUS\G
特别关注 TRANSACTIONS 部分。
如果存在大量 lock wait,说明热点行竞争严重。例如电商场景的库存扣减、账户余额变更,大量事务争抢同一行。
InnoDB 行锁虽然粒度小,但在热点行场景下几乎等同于表锁。CPU 全部耗费在锁管理上了。
再看 BUFFER POOL 部分。Buffer pool hit rate 低于 99%,说明内存不足,频繁从磁盘读取数据,这也会加重 CPU 负担。
排查决策树
用决策树把整个过程串联起来:
使用 top 找到吃 CPU 的进程。如果不是 mysqld,转交开发。
如果是 mysqld,用 vmstat 检查 sy 是否高。sy 高则查看连接数。
sy 正常则检查 wa。wa 高则用 iostat 确认磁盘状况。
wa 正常则检查 us。us 高则查找慢查询。
慢查询正常则用 SHOW PROCESSLIST 检查。有 Lock wait 则排查锁竞争。
避坑清单
- 不要一上来就重启:重启会丢失现场,后续找不到根本原因
- 先保存现场:把 top、vmstat、SHOW PROCESSLIST 的结果先存下来
- 分清 us/sy/wa:us 高是计算问题,sy 高是连接/锁问题,wa 高是磁盘问题
- 监控连接数:连接风暴是 CPU 高的常见元凶
- 关注 Rows_examined:扫描行数远大于返回行数,索引存在问题
- 警惕热点行:库存扣减、余额变更是高频锁竞争场景
- 留意 Buffer pool hit rate:低于 99% 说明内存不足
- 务必开启慢查询日志:没有慢查询日志,排查就是在瞎猜
- 不要只看平均值:一条慢 SQL 就能把 CPU 打满
- 完善监控体系:出事之后第一件事是完善监控,别第二次还是懵的
这些命令看起来不多,但只要完整排查一次故障,就全部记住了。
