深入理解 CPU 使用率:从内核节拍到真实世界的性能分析

35 阅读5分钟

评价一台服务器的 CPU 性能,许多工程师最先想到的往往不是平均负载,也不是上下文切换,而是一个更直观的指标——CPU 使用率
不过,这个看似简单的百分比指标,背后其实藏着非常丰富的系统行为。理解它,是进行性能分析、定位瓶颈、设计高并发系统的重要基础。

这篇文章希望带你从内核节拍的底层原理出发,一步步走向操作实战,讲清楚这些问题:

  • CPU 使用率是怎么计算出来的?
  • 用户态、内核态、iowait、steal 等指标如何理解?
  • 为什么你的 CPU 使用率有时会“假高”?
  • 如何利用 Nginx 压测快速观察 CPU 指标的真实意义?
  • 如何基于 CPU 使用率进行实际性能判断?

一、CPU 时间:由节拍驱动的世界

Linux 是一个多任务系统,它必须将 CPU 时间片公平地分配给不同的任务。但 CPU 本身不会告诉你“现在正在执行哪个进程”,于是 Linux 用了一个很巧妙的方式:时间中断(timer interrupt)

内核会设定一个节拍率(HZ),每过 1/HZ 秒触发一次时间中断。每次中断发生时,全局计数器 jiffies +1。

我的机器上配置为:

$ grep 'CONFIG_HZ=' /boot/config-$(uname -r)
CONFIG_HZ=250

也就是说,每秒触发 250 次时间中断。

用户态应用不用关心这个细节,因为内核还暴露了一个统一的值:

  • USER_HZ = 100

也就是用户态看到的 CPU 统计精度永远是 1/100 秒


二、CPU 使用率来自哪里?——/proc/stat

CPU 使用率的全部基础,都来自 /proc/stat

看一个典型内容:

$ head -n 5 /proc/stat
cpu  226584 5332 87232 4389244 3288 0 1122 0 0 0
cpu0 113292 2601 43021 2194622 1644 0 561 0 0 0
cpu1 113292 2732 44210 2194622 1644 0 561 0 0 0

第一行是所有 CPU 的汇总。

字段依次对应:

字段含义
user用户态(不含 nice)
nice用户态(低优先级 nice)
system内核态执行
idle空闲状态
iowait等待 IO
irq硬中断
softirq软中断
steal被 KVM 抢走的时间
guest运行 guest VM
guest_nice低优先级 guest

所有指标都是累积时间片计数(单位 USER_HZ)。


三、CPU 使用率的真实计算方式

拿两次读取 /proc/stat 的结果:

t1: user1 system1 idle1 …  
t2: user2 system2 idle2 …

则:

delta = 所有字段之差的总和
%user = (user2 - user1) / delta
%system = (system2 - system1) / delta
%idle = (idle2 - idle1) / delta
%iowait = (iowait2 - iowait1) / delta

所有性能工具(top、sar、ps)都依赖这一算法,只是展示方式不同。

这也是为什么:

  • top 显示 CPU 使用率每秒跳一次
  • idle=0 时系统会非常“粘滞”

四、top 中 %user、%system、%iowait 的真正含义

一个常见的误解是:

%user 高说明 CPU 很忙。

其实只有理解每个字段的含义,你才能做出准确判断。

简化解读:

  • %user:业务代码本身在跑。如 JSON 解析、业务逻辑、加密、压缩。
  • %system:内核帮你跑东西。如系统调用、调度、网络协议栈。
  • %iowait:你在等磁盘或网络 IO
  • %steal:你的 CPU 被其他虚拟机偷偷用掉了(云服务器上常见)。

常见几种 “典型 CPU 画像”:

  1. %user 高 ➜ 算力需求高,比如加解密或 CPU 密集型计算
  2. %system 高 ➜ 系统调用频繁,如大量 malloc/free、网络包处理
  3. %iowait 高 ➜ IO 是瓶颈,CPU 不是问题
  4. %steal 高 ➜ 虚拟机资源争抢,换机器吧

五、Nginx 压测:最能显现 CPU 指标的实验

现在进行一个极简的负载实验,用 Nginx 作为被测对象。

  1. 写一个简单的 location:
location /cpu {
    return 200 "OK";
}
  1. 使用 wrk 压测:
wrk -t4 -c200 -d20s http://localhost/cpu
  1. 用 top 观察 CPU 变化。

一个典型现象:

  • 业务非常轻(纯 return),CPU 占用不高
  • %system 明显高于 %user
  • 多核情况下单核被打满

原因来自 Nginx 的模型:

  • Nginx 使用 epoll 和非阻塞 IO
  • 批量处理事件需要做大量系统调用(epoll_wait、accept 等)
  • 系统调用走的是 CPU system 时间

也就是说高并发网络 IO 的系统,%system 才是主战场

如果打开 access log 甚至可能看到:

  • %iowait 上升(log 写盘)
  • qps 降低

通过 sysstat (pidstat -w) 你还能观察上下文切换与 CPU 子项的联动。


六、CPU 使用率的常见误读与真实意义

系统中常见三类“CPU 假象”。

1. CPU 使用率很高,但服务依旧很流畅

这种通常是 %user 或 %system 高,说明 CPU 在干正事。

2. CPU 很低,但请求很慢

往往是:

  • %iowait 高——磁盘打爆了
  • 或者大量线程在锁等待——CPU 状态根本不体现

3. 平均负载很高,但 CPU 使用率很低

大概率是 IO 密集不可中断睡眠(D 状态)


七、如何用 CPU 使用率进行实际系统判断?

CPU 画像与诊断逻辑

如果你看到:

  • %user 高:业务代码是瓶颈
    ➜ 看看是否需要优化算法、减少 JSON 解析、提升缓存命中
  • %system 高:系统调用占比大
    ➜ 通常与网络 IO 有关,要检查 epoll、连接数、sysctl 参数等
  • %iowait 高:IO 阻塞
    ➜ 数据库、磁盘、日志是重点排查对象
  • %steal 高:虚拟化争抢
    ➜ 云上服务器需要迁移

如果你再结合上下文切换(vmstat cs)、RunQueue(r)、slab、tcp metrics,就能用一套完整的 CPU 画像体系分析大部分问题。


八、总结:CPU 使用率是一块透镜,让你看到系统的内在结构

理解 CPU 使用率,你会发现它不仅仅是一个百分比,而是:

  • CPU 多任务调度方式的结果
  • 时间中断节拍的统计
  • 不同内核逻辑之间的时间竞争
  • 硬件与虚拟化层的资源共享方式

它是整个系统运行行为的一种“热成像”。
看懂它,你才能真正看懂你的服务器。