负载高不等于 CPU 忙。任务可能在抢 CPU,也可能卡在磁盘、NFS、内存回收或容器限额里。用这六步,先分清运行、排队和等待,再决定要不要扩容。
先看一组模拟数据。
一台 16 核 Linux 服务器,监控显示 CPU 使用率约为 35%,但 1 分钟负载已经升到 28,接口 P99 也从 200 毫秒涨到了 3 秒。
值班同学觉的 CPU 明明还有很多余量,于是把问题交给数据库团队。数据库团队检查后又说:“慢查询没有增加,可能是服务器负载太高。”
两句话听起来都对,实际上大家混用了两把完全不同的尺子。
先说结论:负载不是 CPU 使用率
CPU 使用率回答的是:过去一段时间,CPU 有多少时间在执行任务。
load average 回答的是:过去一段时间,平均有多少任务处于可运行状态,或者陷入不可中断等待。
Linux 的 /proc/loadavg 会给出 1、5、15 分钟三个平均值。按照 Linux man-pages 的说明,其中统计了运行队列中的 R 状态任务,以及等待 I/O 的 D 状态任务。
所以,负载升高至少有两种完全不同的可能:
- 很多任务没有消耗 CPU,却卡在不可中断的等待里。
第二种情况正是“CPU 看起来不高、负载却一直上涨”的常见来源。
因此,不能看到 load 为 28,就说 CPU 使用率是 2800%;也不能看到 CPU 只有 35%,就认定服务器还有 65% 的可用能力。
同样是“16 核、CPU 35%、负载 28”,背后可能是两条完全不同的故障链。
第一种:任务真的在抢 CPU。
监控的 CPU 曲线被 5 分钟平均,但某几个核实际持续打满。进一步看,会发现运行队列 r 偏高、单核 %idle 接近 0。方向通常是单线程热点、绑核、突发计算或并发过量。
第二种:任务没有运行,而是在等待。
大量请求卡在网络存储,已经不再消耗 CPU。进一步看,会发现阻塞队列 b、D 状态任务和 I/O PSI 同时上升。此时应该检查 NFS、云盘、文件系统、驱动或存储链路。
这也是为什么事故复盘不能只截两张监控图。CPU 使用率要结合采样粒度,负载要拆成 R 与 D,最后还要回到进程、线程和等待点。否则,扩 CPU 可能对第二种情况毫无帮助,甚至会让更多请求更快地涌入同一个阻塞点。
判断顺序很重要:先确认任务处于什么状态,再寻找它等待的资源,最后才讨论扩容、限流或代码优化。顺序反了,团队通常只会得到一次昂贵但无效的变更。
1. 先看核数和时间窗口,别把一个数字单独截图
先执行:
nprocuptimecat /proc/loadavg
假设服务器有 16 个逻辑 CPU,负载是:
28.10 19.42 9.36 3/842 27190
这说明最近 1 分钟的压力明显高于最近 15 分钟,问题可能正在快速恶化。3/842 中的前一个数字,表示读取这一刻处于可运行状态的调度实体数量;后一个数字是当前存在的调度实体总数。
“负载除以 CPU 核数”可以作为观察运行队列压力的粗略入口,但不能直接当成使用率。因为负载中还可能混有 D 状态任务。
团队下一步要问的不是“28 算不算高”,而是:
这 28 个任务主要在抢 CPU,还是在等待别的资源?
2. 检查单核打满和短时尖峰
总体 CPU 使用率是平均值,平均值最容易把局部问题藏起来。
16 核机器上,即使某个绑核线程长期跑满,整机平均值也未必显眼。定时任务、垃圾回收或瞬间并发还可能发生在监控采样之间。
mpstat -P ALL 1pidstat -u1
mpstat、pidstat 和后文的 iostat 来自 sysstat 工具包;如果系统尚未安装,需要先通过发行版的软件包管理器安装。
重点看:
- 是否只有少数 CPU 的
%idle 长期接近 0;
如果只有单核繁忙,应继续检查单线程热点、CPU affinity、IRQ 分布和应用线程模型。此时直接给整台机器加 CPU,可能只是增加更多不会被使用的核。
3. 看运行队列:任务是不是在排队等 CPU
vmstat1
不要急着解读第一行。vmstat 的第一份报告通常是从系统启动以来的平均值,后续行才是每个采样周期的数据。
重点关注:
us、sy、id、wa:CPU 时间分别花在哪里。
如果 r 长期高于可用 CPU 数,而 CPU 也接近繁忙,问题更像是计算资源不足或并发失控。
如果 r 不高,b 却持续增加,就不要再围着 CPU 打转了。任务很可能卡在 I/O 或其他不可中断路径。
4. 找出 D 状态任务,不要只盯着磁盘使用率
可以先把 D 状态任务列出来:
ps-eLo state,pid,tid,psr,comm,wchan:32 |awk'$1=="D"'
D 表示不可中断睡眠,通常与 I/O 等待有关。wchan 可以帮助判断任务睡在什么内核等待点上,但受内核版本和权限限制,有时只会看到 - 或地址。
如果大量任务在同一个等待点堆积,再结合进程名和业务时间线,通常比“磁盘利用率 80%”更接近根因。
还要注意:I/O 不只等于本地磁盘。NFS、CIFS、FUSE、云盘、故障设备以及某些驱动路径,都可能让任务进入长时间的不可中断等待。
所以,D 状态多只能说明“任务被卡住了”,不能仅凭这一列就宣布“磁盘坏了”。
5. 用 I/O 和 PSI 判断:资源到底堵在哪里
先观察块设备:
iostat -xz1
重点结合 await、队列长度、吞吐量和 %util 看趋势。不要把单个 %util=100 当成所有存储设备都已饱和的通用结论;并行设备、虚拟磁盘和云盘还要结合自身架构与延迟基线。
再看 Linux 的 PSI:
cat /proc/pressure/cpucat /proc/pressure/iocat /proc/pressure/memory
PSI 记录任务因为 CPU、内存或 I/O 资源竞争而停顿的时间比例。它能帮助团队回答一个更有价值的问题:
资源压力让业务损失了多少可工作时间?
如果 io 压力持续上升,应继续检查磁盘延迟、网络存储和内核日志;如果 memory 压力上升,同时 vmstat 的 si、so 活跃,则要检查内存回收和交换,而不是只扩 CPU。
如果 /proc/pressure/ 不存在,需要确认内核是否支持并启用了 PSI。不要因为命令没有输出,就直接得出“系统没有资源压力”的结论。
6. 主机 CPU 不高,也可能是容器被限速了
在容器环境里,宿主机还有空闲 CPU,不代表某个容器能继续使用。
cgroup v2 可以这样检查。先从目标进程找到它所属的 cgroup:
cat /proc/<PID>/cgroup
cgroup v2 的输出类似:
0::/system.slice/example.service
再把这个路径接到 /sys/fs/cgroup/ 后面:
cat /sys/fs/cgroup/<cgroup-path>/cpu.maxcat /sys/fs/cgroup/<cgroup-path>/cpu.stat
cpu.max 给出 CPU 带宽上限。例如 50000 100000 表示每 100 毫秒周期最多使用 50 毫秒 CPU 时间;max 100000 表示不设带宽上限。
cpu.stat 中的 nr_throttled 和 throttled_usec 是累计值。间隔几秒读取两次,如果它们在请求变慢期间持续增加,才说明工作负载正在反复触发节流。实际 cgroup 路径由 systemd、容器运行时和部署方式决定。
如果运行在虚拟机中,还要看:
mpstat -P ALL 1
其中 %steal 表示虚拟 CPU 等待宿主机调度、时间被其他虚拟机占用的比例。此时虚拟机内部可能出现运行队列和延迟,但你买到的 vCPU 并没有得到足够的物理 CPU 时间。
一张可以截图保存的排查卡
CPU 不高、Linux 负载高:六步排查
- 看
nproc 和 1、5、15 分钟负载,确认核数与趋势。 - 用
mpstat -P ALL 1 查单核热点和短时尖峰。 - 用
vmstat 1 区分运行队列 r 与阻塞队列 b。 - 用
ps 找 D 状态任务,并结合 wchan 判断等待点。 - 用
iostat -xz 1 和 PSI 区分 I/O、内存与 CPU 压力。 - 检查 cgroup CPU 节流和虚拟机
%steal。
管理者真正要推动的,不是再加一个“负载告警”
如果监控只有“CPU 使用率”和“load average”两条线,事故会上很容易出现这样的对话:
应用说 CPU 不高,系统团队说负载很高,最后大家只能靠经验猜责任。
更有效的做法,是把指标拆成四组:
- 计算供给:逻辑 CPU 数、每核利用率、容器 CPU 配额和节流;
- 环境因素:磁盘延迟、网络存储状态、虚拟机 steal time。
告警也不要只写“load > 10”。至少要带上 CPU 核数、持续时间、运行队列和 PSI,否则收到的只是一个需要人工重新解释的数字。
高负载不是根因,它只是系统告诉你:有很多任务没有顺利完成工作。
下一步不是先决定由谁背锅,而是先确认这些任务究竟在运行、在排队,还是在等待。
你遇到过“CPU 很闲、负载爆表”的机器吗?最后查到的是磁盘、NFS、内存回收、容器限额,还是虚拟化宿主机?欢迎在评论区留下现场特征。
官方资料
- Linux man-pages:
/proc/loadavg - Linux man-pages:
/proc/PID/stat 进程状态 - Linux man-pages:
/proc/stat 与 steal time - Linux Kernel:Pressure Stall Information
- Linux Kernel:Control Group v2
- sysstat 官方项目:
mpstat、iostat、pidstat