当前位置:首页>Linux>CPU 明明不高,Linux 负载为什么还在飙?先检查这 6 个地方

CPU 明明不高,Linux 负载为什么还在飙?先检查这 6 个地方

  • 2026-10-11 06:05:23
CPU 明明不高,Linux 负载为什么还在飙?先检查这 6 个地方

负载高不等于 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,却卡在不可中断的等待里。

第二种情况正是“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;
  • %usr、%sys 的上升集中在哪些核;
  • 某些线程是否持续占用同一个 CPU;
  • 请求变慢的时间点是否出现短促但连续的尖峰。

如果只有单核繁忙,应继续检查单线程热点、CPU affinity、IRQ 分布和应用线程模型。此时直接给整台机器加 CPU,可能只是增加更多不会被使用的核。

3. 看运行队列:任务是不是在排队等 CPU

vmstat1

不要急着解读第一行。vmstat 的第一份报告通常是从系统启动以来的平均值,后续行才是每个采样周期的数据。

重点关注:

  • r:正在运行或等待获得 CPU 时间的任务数;
  • b:等待 I/O 完成而阻塞的任务数;
  • 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 负载高:六步排查

  1. 看 nproc 和 1、5、15 分钟负载,确认核数与趋势。
  2. 用 mpstat -P ALL 1 查单核热点和短时尖峰。
  3. 用 vmstat 1 区分运行队列 r 与阻塞队列 b。
  4. 用 ps 找 D 状态任务,并结合 wchan 判断等待点。
  5. 用 iostat -xz 1 和 PSI 区分 I/O、内存与 CPU 压力。
  6. 检查 cgroup CPU 节流和虚拟机 %steal。

管理者真正要推动的,不是再加一个“负载告警”

如果监控只有“CPU 使用率”和“load average”两条线,事故会上很容易出现这样的对话:

应用说 CPU 不高,系统团队说负载很高,最后大家只能靠经验猜责任。

更有效的做法,是把指标拆成四组:

  • 计算供给:逻辑 CPU 数、每核利用率、容器 CPU 配额和节流;
  • 任务队列:运行队列、D 状态任务数量;
  • 资源停顿:CPU、I/O、内存 PSI;
  • 环境因素:磁盘延迟、网络存储状态、虚拟机 steal time。

告警也不要只写“load > 10”。至少要带上 CPU 核数、持续时间、运行队列和 PSI,否则收到的只是一个需要人工重新解释的数字。

高负载不是根因,它只是系统告诉你:有很多任务没有顺利完成工作。

下一步不是先决定由谁背锅,而是先确认这些任务究竟在运行、在排队,还是在等待。

你遇到过“CPU 很闲、负载爆表”的机器吗?最后查到的是磁盘、NFS、内存回收、容器限额,还是虚拟化宿主机?欢迎在评论区留下现场特征。

官方资料

  • Linux man-pages:/proc/loadavg
  • Linux man-pages:/proc/PID/stat 进程状态
  • Linux man-pages:vmstat
  • Linux man-pages:/proc/stat 与 steal time
  • Linux Kernel:Pressure Stall Information
  • Linux Kernel:Control Group v2
  • sysstat 官方项目:mpstat、iostat、pidstat

最新文章

随机文章