告警响起,CPU跑满,负载几十。这时候最忌讳两件事:上来就重启服务器,或者 top 看一眼然后没有然后了。CPU 打满的排查有清晰的路径:先找到罪魁进程,再钻到线程,最后落到代码或调用栈。每一步都有顺手的工具,顺序别乱。
# 第一步:快照式抓取,按 CPU 排序的前 10 个进程
top -b -n1 | head -17
# 或者更直接:
ps aux --sort=-%cpu | head -11
top 输出里有两个数要分开看:us 是用户态(你的应用代码在干活),sy 是内核态(系统调用、IO),wa 是等磁盘。us 高说明应用代码或某个进程在死循环;wa 高 CPU 其实不忙,是 IO 慢把它衬托的假性打满,排查方向完全不同。锁定进程后,第二步钻进线程——Java、PHP-FPM 这类多线程/多进程程序,往往一个线程在发疯,进程级 top 看不出区别,必须 -H 模式。
# 第二步:线程级视角,找到具体是哪个线程在烧 CPU
top -H -b -n1 -p <PID> | head -20
# 做个对照:pidstat 每 2 秒采样,连续 3 次,看是持续高还是突发
pidstat -u -p <PID> 2 3
# 第三步:看这个进程到底在干什么系统调用(每秒概况)
strace -c -p <PID> -f & sleep 5 && kill %1
strace 的统计结果很有信息量:如果某类调用(比如 read、poll)次数爆炸,基本能定位到是哪个动作在空转。MySQL 进程 CPU 高,直接进库里看 processlist 现场抓 SQL;PHP-FPM 高,看 FPM 状态页和 slowlog。这两条分别在本系列 200 和 195 篇里展开过,这里不重复。
通用场景还有一个杀手锏:perf。它能直接采到热点函数,等于把“谁在烧 CPU”精确到代码行。执行 perf top -p <PID>,最占 CPU 的符号排最前面,C/C++ 程序一目了然。PHP 这类解释执行的程序看到的会是 zend 引擎符号,配合 xdebug 或慢日志定位更好。
# 热点函数采样(perf 需要安装:apt/yum install perf)
perf top -p <PID>
# 落盘分析更从容:采 10 秒生成报告
perf record -F 99 -p <PID> -g -- sleep 10
perf report --stdio | head -30
常见根因清单收个尾:正则回溯灾难(一条 evil regex 吃掉一个 FPM worker)、排序和导出没有分页全量拉数据、缓存失效引发的全库风暴、以及最朴素的那种——代码里写了个 while 忘了退出条件。CPU 打满的案例千变万化,但路径不变:进程、线程、调用栈,三层钻下去,答案就在最底那层。补一句纪律:定位期间别急着改配置,先留证据——top 快照、strace 统计、慢日志,这些是事后复盘和写报告的原材料。
相关阅读:CPU打满是系统层最急的故障。《服务器故障排查总纲:按现象反查的五层定位法》按“先看是谁、再看为什么”的思路排了完整路径,本篇是系统层的主力篇,总纲里有它的兄弟篇 IO wait。
申请创业报道,分享创业好点子。点击此处,共同探讨创业新机遇!
