真实面经题目 · 原创解析

CPU 负载很高但利用率很低,可能是什么原因?

CPU 负载很高但利用率很低,核心原因通常是:load average 统计的是正在运行或等待运行的任务,以及处于不可中断睡眠状态的任务;而 CPU utilization 只反映 CPU 真正在执行用户态、内核态等计算工作的时间占比。因此,很多进程卡在 D 状态、IO wait、磁盘或网络阻塞、锁等待、容器 CPU 配额限制等场景下,系统会表现为 load average 很高,但 CPU 使用率并不高。

出现于:阿里巴巴 · 测开

60 秒回答模板

可以先区分两个指标:CPU 利用率表示 CPU 时间花在计算上的比例,load average 表示系统一段时间内的平均活跃任务数,包括可运行队列里的任务,也包括不可中断睡眠状态的任务。所以负载高不一定代表 CPU 忙,也可能代表大量任务在等资源。常见原因包括磁盘 IO 慢导致进程进入 D 状态、网络存储或远程调用阻塞、数据库或文件系统卡顿、内核态 IO wait 偏高、进程数过多但都在等待、锁竞争导致任务排队、容器 CPU quota 限制导致可运行任务被节流等。排查时我会先用 uptime 或 top 看 load average,再结合 top 里的 us、sy、id、wa、st,判断 CPU 是在计算、等待 IO 还是被虚拟化或容器限制;然后用 ps -eo stat,pid,ppid,comm,wchan:32 排查 D 状态和等待点,用 iostat -x 观察磁盘 util、await、aqu-sz,用 pidstat、iotop、sar、vmstat 判断是哪个进程或资源在阻塞。测试视角下不能只看 CPU 百分比,要结合负载、运行队列、D 状态数量、IO 延迟、容器配额和业务响应时间一起判断瓶颈。

考点 先定义 load average
主线 再定义 CPU utilization
易错点 把 load average 直接等同于 CPU 使用…

深入解析

01

先定义 load average

load average 不是 CPU 使用率,而是过去 1 分钟、5 分钟、15 分钟内系统平均活跃任务数。Linux 中活跃任务不仅包括正在 CPU 上运行或等待 CPU 调度的可运行任务,还包括处于不可中断睡眠状态的任务。也就是说,只要任务没有完成并且处于系统认为不可打断的等待路径中,它就可能推高 load average。判断时要把 load average 和 CPU 核数一起看,例如 8 核机器 load 为 8 大致表示平均有 8 个活跃任务,load 为 40 则说明系统有明显排队或阻塞。

02

再定义 CPU utilization

CPU utilization 衡量的是 CPU 时间被消耗在哪里,例如用户态 us、内核态 sy、空闲 id、等待 IO 的 wa、虚拟化偷取 st 等。CPU 利用率低,通常说明 CPU 大部分时间没有执行计算任务;但这不代表系统健康,因为任务可能都在等待磁盘、网络、锁、内核资源或容器调度额度。面试回答要明确:CPU 利用率低只能说明 CPU 不是主要计算瓶颈,不能说明系统没有瓶颈。

03

D 状态是关键原因

Linux 的 D 状态通常表示不可中断睡眠,常见于等待磁盘 IO、网络文件系统、块设备、内核锁或驱动返回。处于 D 状态的进程不会消耗大量 CPU,但会计入 load average,因此大量 D 状态进程会造成负载很高、CPU 利用率很低。排查时可以执行 ps -eo stat,pid,ppid,comm,wchan:32 | grep '^D',查看哪些进程卡住,以及 wchan 显示它们在等待哪个内核函数。若 D 状态数量持续增长,通常要优先怀疑 IO 子系统、网络存储、文件系统或内核层阻塞。

04

IO wait 会制造假忙现象

当进程发起磁盘读写后等待设备返回,CPU 可能处于空闲或 IO wait 状态。此时 CPU 没有做大量计算,但业务线程无法继续向下执行,load average 仍会升高。典型表现是 top 中 CPU idle 不低或 wa 偏高,同时接口响应变慢、数据库查询变慢、日志写入阻塞或任务堆积。应使用 iostat -x 1 查看 r/s、w/s、await、aqu-sz、%util 等指标,await 高说明 IO 延迟大,aqu-sz 高说明请求队列积压,%util 长期接近 100% 说明设备接近饱和。

05

磁盘和文件系统阻塞

磁盘故障、云盘抖动、写放大、inode 或目录项操作过慢、日志同步写、fsync 过多、文件系统元数据锁竞争,都可能让大量进程阻塞在 IO 路径上。此时业务进程看起来不是 CPU 密集型,但请求完成不了。排查要把应用日志中的慢请求时间点和系统指标对齐,观察 iostat、dmesg、journalctl 是否出现 IO error、reset、timeout、blocked for more than 等信息,并结合 lsof、iotop、pidstat -d 定位高 IO 或被 IO 拖住的进程。

06

网络阻塞也可能推高负载

如果业务依赖 NFS、远程日志、分布式存储、数据库、缓存、RPC 服务或网络挂载目录,网络异常也可能让进程进入长时间等待。尤其是网络文件系统或块存储场景,进程可能在内核态等待返回,从而表现为 D 状态或 IO wait。排查时应结合 ss -antp 查看连接状态,sar -n DEV/TCP 查看网络吞吐、重传和连接情况,检查 DNS、网关、远端服务延迟、存储服务状态,以及应用侧连接池是否被耗尽。

07

进程队列与上下文切换

如果短时间创建大量进程或线程,即使单个任务 CPU 占用不高,也可能让运行队列变长,load average 上升。vmstat 1 中的 r 表示等待运行的任务数,b 表示不可中断睡眠任务数;如果 r 长期大于 CPU 核数,说明 CPU 调度存在排队;如果 b 很高,则更偏向 IO 或内核等待。还要观察 cs 上下文切换和 in 中断数量,过高的上下文切换会带来额外系统开销,但它不一定表现为单个业务进程 CPU 很高。

08

锁等待和资源池耗尽

应用内部锁竞争、数据库锁、连接池耗尽、线程池队列堆积、限流器阻塞,也会让大量请求处于等待状态。严格来说,普通用户态锁等待不一定直接计入 load average,取决于线程状态和等待方式;但它会造成业务层任务堆积,并可能伴随系统线程、IO 或调度等待一起推高负载。排查应结合应用线程栈、jstack、pprof、goroutine dump、数据库锁等待视图、连接池监控和请求队列长度,确认是系统资源阻塞还是应用内部并发控制问题。

09

容器 CPU 配额容易误判

在容器里看到 CPU 利用率低,要确认观察口径。如果容器被设置了 CPU quota,例如只能用 0.5 核或 1 核,而宿主机有很多核,那么从宿主机整体看 CPU 利用率可能很低,但容器内任务已经被 CFS throttling 限制,运行队列变长,load average 或业务延迟升高。排查时要查看 cgroup 的 cpu.max、cpu.stat、nr_throttled、throttled_usec,或通过容器监控观察 CPU throttling。判断瓶颈时应以容器可用 CPU 配额为基准,而不是宿主机总核数。

10

可执行的排查顺序

第一步看 uptime/top,确认 1、5、15 分钟负载趋势和 CPU us、sy、wa、id、st。第二步用 nproc 或 lscpu 确认核心数,判断 load 是否超过可承载范围。第三步用 vmstat 1 看 r 和 b,区分 CPU 排队还是不可中断等待。第四步用 ps 查看 D 状态进程和等待点。第五步用 iostat -x、pidstat -d、iotop 查磁盘 IO。第六步用 ss、sar、应用日志、线程栈或数据库监控继续定位网络、锁、连接池和下游依赖。最后把系统指标和业务耗时按时间线对齐,避免只凭一个指标下结论。

易错点

  • 把 load average 直接等同于 CPU 使用率。
  • 看到 CPU 利用率低就认为系统没有性能问题。
  • 忽略 D 状态进程会计入 load average。
  • 只看 top 的总 CPU,不看 us、sy、wa、id、st 分项。
  • 不结合 CPU 核数或容器 CPU quota 判断负载是否异常。
  • 把 IO wait 问题简单归因为 CPU 不够。
  • 排查时只看单个瞬时指标,不看 1、5、15 分钟趋势。
  • 忽略网络存储、远程数据库、缓存、RPC 等外部依赖造成的阻塞。
  • 没有区分 vmstat 中 r 高和 b 高的不同含义。
  • 压测结论只写负载高,没有给出进程状态、IO 延迟、队列长度和业务延迟证据。

面试官追问

load average 的 1、5、15 分钟分别怎么理解?

这三个值分别表示过去 1 分钟、5 分钟、15 分钟的平均活跃任务数。1 分钟值更敏感,适合看突发压力;5 分钟值能反映压力是否持续;15 分钟值更适合判断长期趋势。如果 1 分钟很高但 15 分钟不高,可能是短时流量尖峰或批任务启动;如果三个值都很高,说明系统已经持续处于排队或阻塞状态。排查时不要只看某一个值,要结合时间趋势和业务变更点判断。

CPU 利用率低但 load 高,第一反应应该查什么?

第一反应应该查任务状态和 IO。可以先看 top 中 wa 是否偏高,再用 vmstat 1 看 r 和 b。如果 b 很高,说明不可中断睡眠任务多,重点查 D 状态、磁盘、网络存储或内核等待;如果 r 很高但 CPU 总利用率看起来不高,要进一步确认是否在容器里被 CPU quota 限制,或者监控口径是不是看了宿主机整体而不是进程或容器维度。

为什么 D 状态进程 kill 不掉?

D 状态通常表示进程正在等待内核里的某个不可中断操作完成,例如等待块设备返回、文件系统完成请求或网络存储响应。此时进程不能响应普通信号,即使发送 kill -9,也要等内核等待点返回后才能真正处理退出。这个设计是为了避免在关键内核路径中被打断导致数据结构不一致。因此 D 状态进程 kill 不掉时,不应只盯着进程本身,而应查它等待的底层资源为什么迟迟不返回。

如何区分 CPU 真不够和 IO 阻塞?

可以从几个指标交叉判断。如果 CPU 真不够,通常 top 中 us 或 sy 较高,vmstat 的 r 长期大于 CPU 核数,应用线程栈中大量线程处于可运行或计算热点,性能分析工具能看到明确的 CPU 热点函数。如果是 IO 阻塞,通常 wa、b、D 状态进程、iostat await、磁盘队列或网络存储延迟异常更明显,CPU 可能有较多 idle。真正排查时要把这些指标和业务延迟时间点对齐,避免把 IO 卡顿误判为需要扩 CPU。

容器里为什么更容易出现这种误判?

因为容器看到的指标可能存在口径差异。宿主机有很多核,整体 CPU 利用率可能很低;但某个容器只分到很小的 CPU quota,容器内部任务已经排队甚至被 throttling。此时从宿主机看 CPU 不忙,从业务看请求却很慢、负载很高。应查看容器的 CPU 配额、cgroup cpu.stat 中的 throttling 次数和时长,并用容器维度的 CPU 使用率与可用配额比较,而不是只看宿主机总 CPU。

压测时遇到 load 高但 CPU 低,测试人员应该怎么记录证据?

测试人员应记录压测时间窗口、并发量、QPS、响应时间、错误率,并同步采集 uptime、top、vmstat、iostat、pidstat、应用日志、线程栈和容器资源指标。重点保留 load 上升时 CPU 分项、wa、r、b、D 状态进程数量、磁盘 await、网络重传、连接池使用率等证据。这样可以证明瓶颈是 CPU 调度、IO 阻塞、下游依赖还是容器配额,而不是停留在机器负载高这种不可执行的描述。