评价一台服务器的 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 画像”:
- %user 高 ➜ 算力需求高,比如加解密或 CPU 密集型计算
- %system 高 ➜ 系统调用频繁,如大量 malloc/free、网络包处理
- %iowait 高 ➜ IO 是瓶颈,CPU 不是问题
- %steal 高 ➜ 虚拟机资源争抢,换机器吧
五、Nginx 压测:最能显现 CPU 指标的实验
现在进行一个极简的负载实验,用 Nginx 作为被测对象。
- 写一个简单的 location:
location /cpu {
return 200 "OK";
}
- 使用 wrk 压测:
wrk -t4 -c200 -d20s http://localhost/cpu
- 用 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 多任务调度方式的结果
- 时间中断节拍的统计
- 不同内核逻辑之间的时间竞争
- 硬件与虚拟化层的资源共享方式
它是整个系统运行行为的一种“热成像”。
看懂它,你才能真正看懂你的服务器。