什么是 CPU 利用率?怎么算的?

#计算机网络#操作系统#面试八股

什么是 CPU 利用率?怎么算的?

CPU 利用率(CPU utilization)是在一段时间内 CPU 非空闲时间的占比,不是瞬时值。 Linux 上它来自内核按 tick 累加的 jiffies 计数器 /proc/stat,采两次求差再相除即可, 所以"利用率"永远是某个时间窗口内的平均值,窗口越短抖动越大。

1. /proc/stat 里的几个计数器

cpu  3357123 1204 88123 99812345 3321 0 4521 0 0 0
     │      │    │     │        │    │   │    │
     │      │    │     │        │    │   │    └ irq 之后新增字段(guest 等)
     │      │    │     │        │    │   └ softirq 软中断
     │      │    │     │        │    └ steal 被宿主机抢走的时间(虚拟机)
     │      │    │     │        └ iowait 等 IO 完成的空闲时间
     │      │    │     └ idle 真空闲
     │      │    └ system 内核态
     │      └ nice 低优先级用户态
     └ user 普通用户态
字段含义是否算"忙"
user用户态执行时间算
nice调整过优先级的用户态时间算
system内核态(系统调用、中断处理)算
idle真空闲不算
iowaitCPU 空闲但仍有未完成磁盘 IO有争议,多数监控不算
irq / softirq硬中断 / 软中断处理算
steal虚拟化环境下被宿主机占走算,但要单独看

2. 计算公式

total = user + nice + system + idle + iowait + irq + softirq + steal
busy  = total - idle - iowait                (常见口径,可再减 steal)
util  = (busy2 - busy1) / (total2 - total1) × 100%

注意 jiffies 的精度:USER_HZ 通常是 100,即一个 tick 10ms。窗口取 1 秒只有 100 个采样点, 再短就没有统计意义。容器里还要看 cgroup 的 cpu.stat,它按真实纳秒记账,比 /proc/stat 准。

3. 代码:自己算一次

// 读两次 /proc/stat,间隔 1 秒算区间利用率
func readCPU() (busy, total uint64) {
    data, _ := os.ReadFile("/proc/stat")
    var user, nice, sys, idle, iowait, irq, softirq, steal uint64
    fmt.Sscanf(strings.Split(string(data), "\n")[0],
        "cpu %d %d %d %d %d %d %d %d", &user, &nice, &sys, &idle, &iowait, &irq, &softirq, &steal)
    total = user + nice + sys + idle + iowait + irq + softirq + steal
    return total - idle - iowait, total
}

b1, t1 := readCPU()
time.Sleep(time.Second)
b2, t2 := readCPU()
fmt.Printf("util = %.1f%%\n", float64(b2-b1)*100/float64(t2-t1))
top -bn1 | head -5                 # 一看 us/sy/id/wa/st
mpstat -P ALL 1 3                  # 每核明细,找单核打满
pidstat -u -p 1234 1               # 单进程 us/sy
cat /sys/fs/cgroup/cpu.stat        # 容器内:usage_usec / nr_throttled

4. 常见追问

Q:iowait 到底算不算忙? 它表示"CPU 空闲但系统里有未完成的磁盘 IO",说明瓶颈可能在磁盘而不是 CPU。 监控上通常单独看 %wa,既不算 100% 忙,也不能当健康。

Q:为什么 top 显示 CPU 100%,但吞吐上不去? 常见三种:单核打满而任务不可并行(看 mpstat 是否有核 100%);大量时间耗在 sy(系统调用、锁竞争); softirq 高(网卡收包太猛,需调 RSS/多队列或开 RPS)。

Q:steal 高说明什么? 说明虚拟机想跑但物理 CPU 被别的租户占着,属于宿主机超卖。此时应用侧再怎么优化也没用, 要看宿主机配额或换规格。

Q:为什么容器里 CPU 利用率常常对不上? /proc/stat 是宿主机全局的,容器内看到的是整机数据;限流(cgroup quota)导致的 throttling 只会体现在 cpu.stat 的 nr_throttled 上,利用率甚至可能只有 50% 却被卡住。

小结

利用率 = 非空闲 tick 占比,数据源是 /proc/stat,必须采两次求差。 真正有价值的是拆开看:us 高说明算得太多,sy 高说明内核/锁太忙,wa 高说明磁盘拖后腿, st 高说明被虚机抢了 CPU。只会说"CPU 100%"是拿不到分的。

笔记加载中…