适用于 Linux 服务延迟升高、CPU 告警或吞吐下降,且需要判断是应用计算、内核开销、虚拟机争用还是 CPU 配额所致的场景。命令基线为 Linux 5.4+、procps-ng 3.3+、systemd 245+;mpstat、pidstat 来自 sysstat 12.2+,perf 为可选工具且应与运行内核兼容。读取其他用户进程、cgroup 和性能事件通常需要 root 或对应权限。先保留告警窗口,不要一开始就重启服务、扩大 CPU 配额或在线执行高开销跟踪。
1. 固定主机、进程与时间边界
date -u
uname -r
systemctl --version | head -n 1
uptime
nproc --all
systemctl status app.service --no-pager -l
systemctl show app.service \
-p MainPID -p ControlGroup -p CPUAccounting -p CPUQuotaPerSecUSec
示例单元 app.service 必须替换为实际名称。MainPID 只代表主进程,prefork、工作进程或边车可能消耗更多 CPU,因此还要按上一步得到的 cgroup 核对完整进程集合。容器环境应从实际运行时取得宿主机 PID、CPU request/limit 和所在 cgroup;容器内看到的 CPU 数量、进程列表与宿主机视图可能不同。
先把 CPU 告警、请求延迟、发布、流量变化和服务重启放到同一 UTC 窗口。累计计数只能做前后差分,不能用事故结束后的单次快照反推峰值。
2. 区分整机饱和、单核热点与虚拟机争用
vmstat 1 10
mpstat -P ALL 1 10
ps -eLo pid,tid,psr,stat,pcpu,comm --sort=-pcpu | head -n 30
mpstat 和 pidstat 未安装时,可先用 vmstat 与 ps 初筛,但 ps 的 %CPU 不是严格的短窗口采样。重点对照:
vmstat的r持续高于可用 CPU 数,且各 CPU 的 idle 都很低,更像整机运行队列饱和。- 只有一个 CPU 接近满载、某个线程长期居首,而其他 CPU 空闲,更像单线程热点、锁竞争后的忙等或 CPU 亲和性限制。
%system、软中断或上下文切换明显升高时,应继续查系统调用、网络包处理、缺页和调度开销,不能只优化业务计算。- 虚拟机中的
%steal持续升高表示 vCPU 等待宿主机调度,应与虚拟化平台同窗口指标核对;来宾机内增加线程通常不会解决宿主机争用。
/proc/pressure/cpu 可补充任务等待 CPU 的压力趋势:
cat /proc/pressure/cpu
PSI 接口依赖内核配置;avg10、avg60、avg300 是不同时间窗口,total 是启动以来的累计等待时间。应记录多次采样的变化,不要把一次累计值当作当前利用率。
3. 单独检查 cgroup v2 配额与节流
先确认 cgroup 版本;以下文件名只适用于 cgroup v2:
stat -fc %T /sys/fs/cgroup
CGROUP="$(systemctl show app.service -p ControlGroup --value)"
cat "/sys/fs/cgroup${CGROUP}/cpu.max"
cat "/sys/fs/cgroup${CGROUP}/cpu.stat"
cat "/sys/fs/cgroup${CGROUP}/cpu.pressure"
只有第一条显示 cgroup2fs 时才按此路径读取;单元名和 ControlGroup 必须来自目标服务。cpu.max 的第一列为 max 时表示没有该层 CPU 带宽上限;数值形式是 quota 与 period。cpu.stat 中 nr_throttled、throttled_usec 持续增加,才说明观察窗口内发生了节流。还要向父 cgroup 逐层核对:子服务自身没有限额,不代表上层 slice、Pod 或容器没有限额。
节流与宿主机饱和可以同时发生。修改 CPUQuota、容器 limit 或编排参数属于容量变更,应先确认业务负载、父层约束和调度策略,再在受控窗口处理。
4. 把热点定位到线程和代码路径
PID=<actual-pid>
pidstat -u -w -t -p "$PID" 1 10
top -H -p "$PID"
PID 必须来自目标实例,进程重启后要重新确认。pidstat -t 用于区分线程,-u 对照用户态与内核态 CPU,-w 观察自愿和非自愿上下文切换。命令行、线程名和符号可能含敏感信息,进入工单或社区前应脱敏。
需要调用栈时,优先使用应用运行时自带且已验证开销的 profiler。具备授权、性能事件权限并评估开销后,才考虑短时采样:
perf --version
sudo perf record -F 99 -g -p "$PID" -- sleep 30
sudo perf report --stdio
perf 可能受 kernel.perf_event_paranoid、符号文件、容器权限和编译选项限制;空符号或不完整调用栈不等于没有热点。不要在未知负载下长时间提高采样频率,也不要用 strace 全量跟踪来替代 CPU profiling。
5. 验证闭环
处置后用相同采样周期重复 vmstat、mpstat、pidstat 和 cgroup 计数,确认比较的是同一实例、同一 CPU 配额与相近业务负载。至少同时验证:热点线程 CPU 降低或吞吐按预期提高;运行队列、PSI 与请求延迟回落;nr_throttled 不再异常增长;虚拟机 %steal 或宿主机争用已由平台侧证据解释;错误率和尾延迟没有因降载或限流转移到其他组件。
只看到总 CPU 下降不算闭环。还应记录根因属于代码路径、并发模型、cgroup 配额、宿主机调度还是内核开销,并把容量阈值、回归压测和告警口径与该根因对应起来。