这条排查路径解决什么
服务器变卡或 CPU 告警时,要回答三个问题:谁在吃 CPU、吃的是一条线程还是整个进程、这是不是有意义的计算。路径是先看整机指标(top 头部的各项占比、load average),再定位进程,接着下钻到线程,最后确认进程身份与启动方式,再决定降优先级、限流还是重启。
基本信息
| 适用场景 | 整机变卡、CPU 使用率告警、单核跑满 |
|---|---|
| 关键工具 | top、ps、top -H、pidstat、taskset、renice |
| 核心判据 | %us 是否高、load 与核数的关系、%wa 与 %st 占比 |
| 处置手段 | renice 降优先级、taskset 换核、cgroup 或 cpulimit 限流,均为临时缓解 |
典型使用场景
- 整机负载高先分方向:load 高且 %us 高是真在算,load 高但 CPU 空闲说明大量进程卡在 D 状态等 IO
- 定位进程:top 按 %CPU 排序,或用 ps --sort=-pcpu 一次取前几名
- 定位线程:top -H 看进程内部哪条线程占满单核,Java 场景再对 jstack 的 nid
- 确认身份:lstart 与 cmd 判断是业务进程还是备份、编译类一次性任务
- 临时缓解:降优先级或限核,为定位与修复争取时间
进程级定位
进程级定位
top -b -n1 -o %CPU | head -15 # 非交互取一轮,按 CPU 排序
ps -eo pid,ppid,user,pcpu,pmem,etime,cmd --sort=-pcpu | head -10
pidstat -u 1 5 # 每秒采样,看瞬时占用线程级定位
线程级定位
top -H -p 1234 # 该进程内部哪条线程最热
ps -L -p 1234 -o pid,tid,psr,pcpu,comm --sort=-pcpu | head
printf '0x%x\n' 12457 # 热线程 TID 转十六进制,对应 jstack 的 nid
taskset -p 1234 # 查看进程的 CPU 亲和性绑定关键指标读法
| 指标 | 含义 | 正常与异常 |
|---|---|---|
| %us / %sy | 用户态与内核态 CPU 占比 | %sy 长期偏高常见于频繁系统调用、上下文切换或中断密集 |
| %wa | 等待 IO 的 CPU 占比 | 偏高说明瓶颈在磁盘而非 CPU,不要急着杀进程 |
| %st | 被宿主机偷走的 CPU | 虚拟机偏高说明同宿主机邻居在抢资源,只能找云厂商 |
| load average | 1/5/15 分钟可运行加不可中断进程数均值 | 要与核数对比;超过核数且 %us 不高时多为 IO 等待 |
| %CPU(ps) | 进程生命周期内的平均占用 | 短命进程会被稀释,看瞬时要用 top 或 pidstat |
| 单核 100% | 整机空闲但一条线程跑满 | 典型单线程瓶颈,检查是否绑核或存在串行处理 |
单核 100% 而整机 CPU 有余时,方向是多线程模型或绑核问题:用 taskset -p 看亲和性、看进程是否只有一条工作线程;多核全满则看是否 fork 风暴(pstree 看子进程数)或并发配置过高。
动手前先判断业务影响:CPU 高可能正是编译、备份、批量导入等有价值计算。贸然 kill -9 会留下不一致数据。优先用 renice 降优先级或 cgroup 限流,把「定位」和「处置」两步分开做。