深色模式
CPU 飙高排查
摘要:CPU 飙高可能是死循环、频繁 GC、锁竞争或宿主机争抢,症状相似但处置完全不同。本文按"整机 → 进程 → 线程 → 函数"四级递进,给出可直接复制的命令,并说明各类 CPU 时间的真实含义。
适用环境
bash
which top pidstat perf vmstat
grep -c ^processor /proc/cpuinfo
top -b -n 1 | head -121
2
3
2
3
排障步骤
第 1 步:看整机 CPU 与 load
bash
top -b -n 1 | head -12
vmstat 1 51
2
2
关注 us(用户态)、sy(内核态)、wa(等 IO)、si/hi(中断)、st(被宿主机偷走)。st 持续偏高说明是宿主机争抢,本机排查无效。
第 2 步:找热点进程
bash
ps -eo pid,ppid,pcpu,pmem,stat,etime,comm --sort=-pcpu | head -15
pidstat -u 1 51
2
2
多核下 %CPU 可以超过 100%
单进程显示 200% 表示占满 2 个核,属正常表达方式,除以核数才是真实占比。
第 3 步:找热点线程
bash
top -H -b -n 1 -p <PID> | head -25
pidstat -tu 1 3 -p <PID>1
2
2
第 4 步:线程号转十六进制,抓调用栈
Java 线程在 jstack 中以十六进制 nid 标识:
bash
printf '%x\n' <TID>
jstack -l <PID> > /tmp/jstack.txt
grep -A 25 'nid=0x<hex>' /tmp/jstack.txt1
2
3
2
3
间隔 5 秒连抓 3 次,反复出现在同一位置的栈即热点。
第 5 步:用 perf 看函数级热点
bash
perf top -p <PID>
perf record -F 99 -g -p <PID> -- sleep 30
perf report --stdio1
2
3
2
3
perf 的前提与开销
perf record 有少量额外开销,极敏感业务慎用;符号缺失时只会看到地址,需安装对应内核与应用调试符号;容器内需放开 perf_event_open 或以特权模式运行。
第 6 步:判断是"忙"还是"等"
bash
grep -E 'State|Threads' /proc/<PID>/status
awk '{print $3}' /proc/<PID>/stat # R=运行 D=等IO S=睡眠1
2
2
wa 高且存在大量 D 状态进程,本质是 IO 问题,加 CPU 无效。
验证
bash
uptime
top -b -n 1 -p <PID> | tail -2
pidstat -u 1 31
2
3
2
3
常见坑
把 iowait 当成 CPU 问题
wa 高应转向磁盘排查,盲目调 CPU 配额无效果。
容器内 top 显示的是宿主机视图
容器内 /proc/stat 通常反映宿主机全量 CPU,应结合 cgroup 的 cpu.stat 判断实际用量与限流次数。
频繁 GC 被误判为业务代码问题
表现为 CPU 高但吞吐低,应同时看 GC 日志与堆使用率,而不是只优化业务代码。
直接在生产 kill -9 热点进程
会造成请求中断与数据不一致。优先摘流、扩容、回滚,重启作为最后手段。