CPU 使用率低但 load 高,可能的原因有哪些,如何一步步定位
解读
国内面试官问这道题,核心想验证三件事:
- 对 Linux load 本质的理解(TASK_UNINTERRUPTIBLE 任务也会算进去);
- 能把“低 CPU”与“高 load”这一对看似矛盾的现象,拆成可度量的子问题;
- 有系统化的现场排查思路,而不是一上来就“重启试试”或“换台机器”。
回答时先给“可能原因”分类,再给“可落地的定位步骤”,最后能反推业务影响,基本就能拿到高分。
知识点
- Linux load average:1/5/15 分钟内活跃与不可中断态任务数的指数加权移动平均。
- 不可中断态(D 态):通常等在 I/O、NFS、锁、raw socket、swap-in、raid 卡、dm 层、内核 mutex。
- CPU % 与 load 无必然关系:CPU 空闲但大量任务卡在 D 态,load 依旧飙高。
- 国内云环境常见“隐形 I/O”:超卖云盘、共享存储 QoS 限流、KVM virtio-block 队列打满、容器 cgroup blkio throttle。
- 排查工具链:top/htop(D 态标记)、vmstat 1(procs 列 b)、dstat -cldmnsy 1、pidstat -d 1、iostat -xm 1、perf top、/proc/PID/stack、/proc/sys/fs/file-nr、lsof、strace -f -p、sysrq+w、ebpf(biosnoop、runqlat)、ftrace、perf sched。
- 国内合规要求:生产网多数禁用外源包,优先用系统自带或公司源里的 perf/bcc;定位报告需脱敏,不能带客户 ID、订单号。
答案
一、可能原因(按出现频率从高到低)
- 磁盘或云盘 I/O 长时间得不到响应,大量任务进入 D 态;
- 内存不足触发 swap-in/swap-out,磁盘成为瓶颈;
- NFS/CIFS、NAS 挂载点网络抖动,远端无响应;
- 容器 blkio throttle 或 cgroup io.max 限制过低,队列堆积;
- 内核锁竞争(inode、ext4 journal、nvme 驱动 mutex、raid 卡 firmware bug);
- 超线程核饥饿,任务一直在 runnable 态排队,但 CPU 统计里算 idle;
- 僵尸进程过多,父进程不回收,导致 task struct 不释放;
- 内核 bug(已知 3.10-693 与 4.19 某批次 xfs 死锁)导致 D 态永久睡眠。
二、定位步骤(现场可操作,5 分钟出方向,15 分钟出根因)
Step0 确认现象
top 或 htop 观察 1 分钟:CPU idle>70%,但 load 15 以上;同时看“Tasks”行 D 态数量。
Step1 区分是“D 态堆积”还是“ runnable 排队”
vmstat 1 看 procs 列:
b 列持续 > cpu 核数 → D 态;
r 列持续 > cpu 核数 → runnable 排队。
Step2 若 b 列高,立即找谁在等 I/O
dstat -cldmnsy 1 或 iostat -xm 1:
await>100 ms 且 %util≈100 → 磁盘/云盘瓶颈;
svctm 接近 await → 设备慢;
aqu-sz 持续 > 核数 → 队列堆积。
pidstat -d 1 定位进程:看 kB_rd/s、kB_wr/s 最高者。
Step3 确认是否 swap 引起
free -m 看 swap used 是否波动;
si/so 列在 vmstat 中是否非 0;
cat /proc/PID/status 的 VmSwap 是否很大。
Step4 若 NFS/CIFS
mount | grep -E 'nfs|fuse' 找到挂载点;
nfsstat -c 看 retrans 是否持续增长;
tcpdump -i eth0 port 2049 看重传。
Step5 容器场景
cat /sys/fs/cgroup/blkio/docker/*/blkio.throttle.read_bps_device
若值很小,直接 echo 调大或让运维改 kubelet --cgroups-per-qos;
kubectl top pod + crictl inspect 找到容器内部 pid,再回宿主机看 /proc/PID/stack。
Step6 锁竞争或内核 bug
perf top -g 看是否 _raw_spin_lock、ext4_journal_start 占头;
cat /proc/PID/stack 反复采样,若总在 io_schedule 或 mutex_lock 同一函数 → 锁;
对比 RedHat/CentOS 官方 kernel errata,看是否已修复。
Step7 给出量化结论
记录“D 态任务数=xx、磁盘 await=xx ms、swap si/so=xx、NFS retrans=xx”,
明确根因:如“云盘单盘 IOPS 被限 800,业务峰值需 3000,导致 平均 D 态 120 个,load 飙到 32”。
Step8 推动优化
短期:升配云盘 IOPS、加内存关 swap、cache 预热;
长期:业务层做分库分表、异步刷盘、本地 SSD cache、读链路加 Redis。
拓展思考
- 如果现场只能保留 3 个命令,你会留哪 3 个?
答:top(看 D 态)、vmstat 1(r/b 列)、iostat -xm 1(await/util)。理由:10 秒内就能判定是 CPU 排队还是 I/O 排队,决定后续方向。 - 云厂商超卖场景下,iostat 显示 %util 很低但 await 很高,如何说服运维不是“应用写大了”而是“后端限流”?
答:用 fio 做 4 k 随机读,iodepth=1,直接压裸盘,若 latency 与业务进程一致,说明云盘侧 QoS 限速;同时把云监控 API 的 VolumeReadLatency 截图附在报告里,形成“三证据”链。 - 容器内 pid 看到的 D 态栈是 vfs_read->nfs_readpage,但宿主机上该 pid 不存在,怎么继续?
答:容器 pid ns 独立,需在宿主机用 nsenter -t <container-pid> -p cat /proc/1/stack,或在宿主机用 perf record -e sched:sched_blocked_reason -a 抓取 ns 间映射,再反解容器内业务进程。