负载与 CPU 判读:load、top、vmstat

load average 是被误读最多的指标:它高不代表 CPU 忙,它低也不代表系统健康。本章讲清 load 的构成(Linux 把不可中断的 D 状态也算进去)、top 各列的含义、vmstat 的读法,以及“load 高但 CPU 不高”这类经典问题的排查路线。

load average 到底是什么

uptime 输出的三个数字是 1 分钟、5 分钟、15 分钟的平均“可运行 + 不可中断”进程数。

load 的组成 = R(可运行,等 CPU)+ D(不可中断睡眠,通常在等 IO)
注意:Linux 的 load 包含 D 状态;传统 UNIX 只算 R 状态,所以两边的 load 不可直接比较
现象含义说明
1 分钟 > 15 分钟负载正在上升刚发生的变化,优先看最近变更与流量
1 分钟 < 15 分钟负载正在回落可能是瞬时尖峰,也可能是扩容起了作用
三者接近且都高持续过载容量真的不够,需要扩容或优化
三者都低但延迟高不是负载问题去查锁、网络、下游依赖与 GC

load 要和核数一起看

核数load 值判断
41大约用掉 25% 的处理能力,健康
44队列已满,请求开始排队,延迟抬头
48平均每个核有 2 个任务在等,延迟翻倍级恶化
420+严重过载,通常伴随超时与雪崩

经验阈值:load 持续高于核数的 1.5 倍就该介入,高于 3 倍必须止血。注意容器场景下 load 是宿主机级别的,容器内看到的 load 可能与本容器无关,此时应改用 cgroup 的 CPU 限流指标(cpu.stat 里的 nr_throttled)判断。

load 高但 CPU 不高:先找 D 状态

这是最经典的分叉点,答案几乎总在等待 IO 或等待锁。

# 谁在 D 状态(不可中断睡眠)
ps -eo state,pid,ppid,comm,wchan:24 | awk '$1=="D"'

# 确认是否 IO 等待
vmstat 1 5
iostat -x 1 3
pidstat -d 1 3
load 高 + CPU 表现结论下一步
CPU 也高(us+sy 接近核数×100%)计算型过载top -Hp <pid> 找热点线程,再上火焰图
CPU 低,%wa磁盘或网络存储慢iostat -x 1%utilawait
CPU 低,%wa 也低,D 进程多等锁、等 NFS、等内核态资源strace -cp <pid>cat /proc/<pid>/wchan
CPU 低,%si软中断处理不过来查网卡流量、丢包与小包攻击
容器内 load 高、宿主正常cgroup 被限流cpu.statnr_throttledthrottled_time

top 各列怎么读

含义判读要点
us用户态 CPU 占比高说明业务代码在算,去看火焰图
sy内核态 CPU 占比高说明 syscall、锁争用、内存分配频繁
ni调整过优先级的用户态占比一般很低,高说明有人在跑 nice 任务
id空闲占比与 us+sy+wa 互补
wa等待 IO 占比高即磁盘饱和,配合 iostat -x 确认
hi硬中断占比高常见于网卡、磁盘中断过多
si软中断占比高常见于高 PPS 流量或网络攻击
st被虚拟化偷走的 CPU云主机高说明宿主机超卖,只能联系云厂商
%CPU(进程区)单进程 CPU 占用可能超过 100%,多线程进程在多核上总和不封顶
RES进程实际物理内存排查内存时看这一列,不看 VIRT
S进程状态R 运行、D 不可中断、S 睡眠、Z 僵尸

看到 %CPU 是 380%,说明这个进程同时用了约 4 个核,不代表数据错误。要定位到具体线程:

top -Hp <pid>          # 线程级,SPID 即线程 ID
top -Hp <pid> -b -n 1 -o %CPU | head -25
printf '%x\n' <tid>    # 转十六进制后去线程栈里搜 "nid=0x..."

vmstat 列判读

vmstat 1 第一行是开机以来的均值,从第二行起才是每秒的瞬时值,别拿第一行做判断。

含义阈值与结论
r运行队列长度(等 CPU 的进程数)持续大于核数 → CPU 不够
b阻塞进程数(多为 D 状态)持续大于 0 → 有 IO 或锁阻塞
si / so每秒换入/换出内存(KB)非 0 且持续 → 内存不足,延迟必抖
bi / bo每秒块设备读入/写出(块)结合 iostat 判断是否磁盘打满
in每秒中断数突增查网卡与磁盘中断
cs每秒上下文切换数远高于平时 → 锁竞争或线程数过多
us / sy用户态/内核态占比sy 高查 syscall,us 高查代码
id / wa空闲/IO 等待占比wa 高即磁盘瓶颈
st被偷走的 CPU云主机上高说明邻居在抢占

上下文切换的经验值:几万次/秒在 8 核机器上正常;如果 csr 一起暴涨且 CPU 不高,多半是锁竞争或线程池开太大,而不是算力不够。

# 一次采集,同时留下 CPU、上下文切换、队列三组数
vmstat 1 10 > /tmp/vmstat.txt
pidstat -w 1 5        # 哪个进程在疯狂切换
mpstat -P ALL 1 3     # 是否只有个别核忙

处置动作

场景立即动作后续动作
计算型过载限流、降级非核心接口、扩容火焰图定位热点函数并优化
IO 等待导致 load 高减少写入(降日志级别、关埋点)换 SSD、拆分数据目录、优化大查询
锁竞争回滚最近改动、临时降并发缩小锁粒度、拆分热点 key
软中断高限流入口、加网卡多队列与 RPS排查异常小包流量
容器被限流提 CPU limit 或加副本调整 request/limit 比例

预防与巡检

  • 把 load 按核数归一化成“每核负载”再设告警,避免不同规格机器共用一套阈值。
  • 同时采集 us/sy/wa 三项,只报 load 的告警无法区分计算型还是 IO 型过载。
  • 记录每次发布前后的 load 基线,容量规划靠数据不靠感觉。
  • 云主机与容器务必单独看 stnr_throttled,否则会把平台问题当成自己的问题。

小结:load 是“排队任务数”而不是 CPU 使用率,Linux 的 load 还包含 D 状态;判断时先除以核数,再分叉到 CPU、IO、锁、软中断四条路径;top 的 %CPU 可以超过 100%,定位到线程后转十六进制查栈;vmstat 从第二行起读,重点看 rbsi/socswasi/so 一旦持续非 0,延迟问题就找到了主因。

笔记加载中…