
线上服务器收到 CPU 告警时,第一反应往往是直接重启进程。这样能恢复服务,但现场没了,问题还会复发。本文整理一套从系统到线程的定位步骤,所有命令均为常见发行版自带或可通过 sysstat 安装。
load average 统计的是运行队列加上不可中断睡眠(D 状态)的任务数,并不等于 CPU 使用率。
uptime
nproc
vmstat 1 5load 持续大于 nproc,说明任务在排队。vmstat 的 r 列高、us/sy 高:CPU 密集。b 列高、wa 高:多半是磁盘或网络 IO 拖慢,需要转去查 IO,而不是查 CPU。cs(上下文切换)异常大:可能是线程过多或锁竞争。top -b -n 1 | head -20
pidstat -u 1 5top 里按 P 按 CPU 排序;1 展开每个核心,观察是否只有单核被打满。pidstat -u 区分 %usr(用户态)与 %system(内核态)。内核态占比高时,常见原因是大量系统调用、频繁的网络收发或内存回收。top 看到的是宿主机进程,需要用 docker stats 或 cat /sys/fs/cgroup/cpu.stat 确认是否触发了 CPU 限流(nr_throttled)。找到高 CPU 进程 PID 后,进一步看线程:
top -H -p <PID>
pidstat -t -p <PID> 1 5记下占用最高的线程 TID。
printf '%x\n' <TID>
jstack <PID> | grep -A 20 'nid=0x<十六进制TID>'jstack 输出里的 nid 就是十六进制线程号。若线程名是 GC Task Thread,说明问题在 GC,应转去看堆与 GC 日志,而不是业务代码。
net/http/pprof,使用 go tool pprof http://host:port/debug/pprof/profile?seconds=30。py-spy dump --pid <PID> 或 py-spy top --pid <PID>,无需改代码、对进程影响小。perf top -p <PID> 查看热点函数。perf record -F 99 -p <PID> -g -- sleep 30
perf report --stdio | head -50采样频率不要设得过高,生产环境建议 99 Hz 左右并限制采样时长。火焰图可用 perf script 输出后交给 FlameGraph 工具生成。
现象 | 常见原因 | 处理方向 |
|---|---|---|
单线程 100% | 死循环、正则回溯、热点计算 | 抓栈定位代码,加超时或优化算法 |
多线程均高 | 请求量突增、缓存失效后回源 | 限流、预热缓存、扩容 |
sy 占比高 | 频繁系统调用、小包网络 IO | 合并写、批量处理、调整连接池 |
GC 线程高 | 堆过小或内存泄漏 | 调整堆参数,分析 heap dump |
容器内高但宿主机正常 | CPU limit 过低被限流 | 调整 limits 或排查并发配置 |
重启之前至少保存以下信息,便于事后复盘:
mkdir -p /tmp/cpu-case && cd /tmp/cpu-case
top -b -n 1 > top.txt
pidstat -u -t 1 10 > pidstat.txt
jstack <PID> > jstack.txt # 仅 Javajstack、perf 会对进程产生一定开销,先在单实例上操作,避免多实例同时执行。排查顺序可以固定为:先判断是 CPU 密集还是 IO 等待,再定位进程,再定位线程,最后用栈或 perf 找到热点代码。每一步都有可对照的数据,比凭经验猜测更可靠。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。