定位 Linux「CPU 突然飙高」的四步排查法
凌晨两点收到「接口变慢」的告警,登上去一看 load 12。这种时候最怕两种反应:一是直接重启,二是凭感觉改代码。CPU 飙高的定位其实有固定套路,四步就能把范围从「整台机器」收窄到「某一行代码」。
第一步:确认是真的忙,还是被平均了
先看 top -b -n1 | head -20 里的 us / sy / wa。us 高是用户态在算,sy 高多半是系统调用或中断,wa 高说明根本是 I/O 在拖,CPU 背了锅。
再用 mpstat -P ALL 1 5 看每颗核。只有一颗核 100%、其余闲着,基本可以锁定单线程死循环;所有核一起飞,才是并发任务或流量上涨。
第二步:锁定进程
pidstat -u 1 5 按 %CPU 排序,把嫌疑进程挑出来。顺手看一眼 %usr 和 %sys 的比例:一个 Java 服务 %sys 长期偏高,通常是日志刷盘或大量小对象触发的系统调用,而不是业务计算。
第三步:从进程缩到线程
top -H -p <pid>,或者 ps -L -o tid,pcpu,comm -p <pid> --sort=-pcpu | head。拿到线程号后转十六进制:printf '0x%x\n' <tid>,再去 Java 线程栈里搜 nid=0x...,就能把 CPU 最高的线程和一个具体方法对上。
取栈优先用 jcmd <pid> Thread.print,它比 jstack -F 温和。生产环境连续取三次、间隔 5 秒,三次都停在同一处的才是热点,只出现一次的是瞬时抖动。
第四步:采样看热点函数
perf top -p <pid> 实时看,或者 perf record -F 99 -g -p <pid> -- sleep 30 采样 30 秒,再 perf report 看调用链。火焰图上那段又宽又平的栈,就是答案。
三个容易误判的坑
一是容器里的核数。top 显示的是宿主机核数,%CPU 能超过 100%,先查 cgroup 配额再判断有没有「跑满」。二是 GC 线程。%CPU 高、业务线程栈却都空闲,八成是 GC 在刷,直接 jstat -gcutil <pid> 1000。三是符号缺失。perf 只显示十六进制地址时,检查 /proc/sys/kernel/perf_event_paranoid 是否大于 2,以及二进制有没有带调试符号。
把它变成一条命令
这四步每次手敲太慢,写成脚本把 top 快照、pidstat、线程栈、perf record 一起落到 /tmp/cpu-YYYYmmdd-HHMM/ 下,事后复盘和定位都有依据。
定位问题的价值不在于找到凶手,而在于让下一次不用再找:把采集脚本和判定阈值沉淀下来,告警响起时人只做决策,不做体力活。
- 点赞
- 收藏
- 关注作者
评论(0)