4、CPU瓶颈定位:CPU使用率分析、上下文切换、运行队列、软中断、硬中断

说到CPU瓶颈,很多人第一反应就是看使用率。但说实话,光看使用率远远不够。我见过太多案例,CPU使用率才30%,系统却慢得像蜗牛。为什么?因为真正的瓶颈往往藏在那些你看不见的角落里。

这一节,我带你把这几个关键指标掰开揉碎了讲清楚。你想想看,CPU就像一条高速公路,使用率只是告诉你路上有多少车,但真正影响通行效率的,是堵车、是频繁的并线、是突发的交通事故。

4.1 CPU使用率分析——别被数字骗了

CPU使用率,说白了就是CPU忙活的时间占比。但这里有个坑——使用率高不等于有问题,使用率低也不等于没问题。

我习惯把使用率拆成三块来看:

  • 用户态(user):跑应用程序的时间。比如你的Java进程、Nginx进程。
  • 系统态(sys):内核干活的时间。比如系统调用、内存分配。
  • 等待I/O(iowait):CPU在等磁盘或网络数据。这个值高了,说明I/O才是真凶。

用top命令看一眼:

# 按1查看每个CPU核心
top - 09:15:33 up 10 days,  2:15,  3 users,  load average: 2.50, 2.30, 2.10
%Cpu(s): 65.0 us, 20.0 sy,  0.0 ni, 10.0 id,  5.0 wa,  0.0 hi,  0.0 si,  0.0 st

你看这个例子,us 65%,sy 20%,wa 5%。系统态占了20%,这就不太正常了。我在项目中遇到过类似情况,最后发现是一个程序疯狂调用gettimeofday(),每秒几万次系统调用,直接把sys打爆了。

核心判断逻辑:

  • us高 → 应用层瓶颈,优化代码或扩容
  • sy高 → 系统调用频繁,检查锁、上下文切换
  • wa高 → I/O瓶颈,先查磁盘或网络
  • id低 + us低 + sy低 → 大概率在等锁

4.2 上下文切换——看不见的性能杀手

上下文切换,就是CPU从一个任务切到另一个任务。每次切换都要保存寄存器、加载新状态,这开销可不小。

用vmstat看上下文切换频率:

# 每秒输出一次
vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 2  0      0 1623456  1234 567890    0    0    10    20 1500 8000 30 20 50  0  0

注意cs这一列,表示每秒上下文切换次数。8000次/秒,这个值已经偏高了。一般来说:

  • 单核CPU:cs < 5000 算正常
  • 多核CPU:cs < 10000 算正常
  • 超过20000,基本可以断定有问题

为什么会这么高?我总结了几种常见情况:

  1. 线程数过多:一个进程开了几百个线程,互相抢CPU
  2. 锁竞争激烈:线程频繁加锁解锁,导致被迫切换
  3. 定时器太多:高精度定时器会触发大量中断

我的排查习惯:先用pidstat -w 1看哪个进程的cswch(自愿切换)和nvcswch(非自愿切换)最高。自愿切换高,说明在等资源;非自愿切换高,说明时间片被抢了,线程太多了。

4.3 运行队列——CPU到底有多忙

运行队列(run queue)表示正在排队等CPU的任务数。这个指标比使用率更能反映CPU的真实压力。

用uptime或top看load average:

uptime
 09:30:22 up 10 days,  2:30,  3 users,  load average: 4.50, 3.80, 3.20

load average后面的三个数,分别是1分钟、5分钟、15分钟的平均运行队列长度。怎么判断是否过载?

一个简单的公式:load average / CPU核心数 > 0.7 就要警惕,> 1.0 说明CPU已经忙不过来了。

举个例子,4核CPU,load average 4.5,意味着平均有4.5个任务在排队。4核只能同时跑4个,多出来的0.5个在等。嗯,这已经有点挤了。

注意:load average高不一定就是CPU瓶颈。如果进程在等I/O(D状态),也会计入load。我曾经遇到一个案例,load飙到30,CPU使用率才10%,最后发现是NFS挂载点挂了,一堆进程卡在I/O等待上。

4.4 软中断与硬中断——打断CPU的“不速之客”

中断,就是硬件或软件突然打断CPU,让它去处理紧急事情。分两种:

  • 硬中断(hi):硬件发起的,比如网卡收到数据包、磁盘完成读写
  • 软中断(si):内核发起的,比如网络协议栈处理、定时器

用cat /proc/interrupts看硬中断分布:

cat /proc/interrupts
           CPU0       CPU1       CPU2       CPU3
  0:        123          0          0          0   IO-APIC   2-edge      timer
  1:         10          0          0          0   IO-APIC   1-edge      i8042
 27:     456789     123456          0          0   PCI-MSI 512000-edge      eth0

你看,网卡中断(eth0)几乎都打在CPU0和CPU1上,CPU2和CPU3闲着。这就是典型的中断不均衡问题。

软中断可以用cat /proc/softirqs查看:

cat /proc/softirqs
                    CPU0       CPU1       CPU2       CPU3
          HI:          0          0          0          0
       TIMER:    1234567    1234567    1234567    1234567
      NET_TX:      12345      12345      12345      12345
      NET_RX:     987654     987654     987654     987654
       BLOCK:        123        123        123        123
    TASKLET:          0          0          0          0
      SCHED:     2345678    2345678    2345678    2345678

重点关注NET_RX(网络接收)和BLOCK(块设备)。如果某个CPU的NET_RX特别高,说明网络流量都压在一个核上。

解决方案:

  • 硬中断不均衡 → 设置irqbalance服务,或手动绑定中断到不同CPU
  • 软中断过高 → 开启RPS(Receive Packet Steering),让软中断分散到多核
  • 网络软中断打满单核 → 使用多队列网卡,配合RSS(Receive Side Scaling)

4.5 一张图看懂CPU瓶颈定位

下面这张图,是我自己总结的CPU瓶颈排查流程。你照着走一遍,基本不会漏掉关键点。

CPU瓶颈定位排查流程图 发现性能问题 第一步:看CPU使用率 (top) us高?sy高?wa高?还是id低但us/sy都低? 使用率正常? 是 第二步:看运行队列 (uptime) load / 核心数 > 0.7? 否 第二步:深入分析使用率 us高→应用优化 | sy高→上下文切换 第三步:看上下文切换 (vmstat) cs > 10000?自愿/非自愿切换? 第四步:看软/硬中断 /proc/interrupts | /proc/softirqs 第三步:检查D状态进程 ps aux | grep " D" 看是否在等I/O 定位瓶颈类型,制定优化方案 应用优化 / 扩容 / 中断均衡 / 减少线程数

4.6 实战排查清单

最后,给你一份我平时用的排查清单。遇到CPU问题,按这个顺序来:

步骤 命令 看什么 阈值
1 top us/sy/wa/id sy > 30% 或 wa > 20% 需关注
2 uptime load average load/核心 > 0.7
3 vmstat 1 r(运行队列)、cs(切换) r > 核心数*2 或 cs > 10000
4 pidstat -w 1 自愿/非自愿切换 非自愿切换占比高 → 线程过多
5 cat /proc/interrupts 中断分布是否均衡 单个CPU处理80%以上中断
6 cat /proc/softirqs NET_RX、BLOCK 单个CPU软中断异常高

一个小技巧:我习惯把top的显示模式改成按CPU使用率排序(按P键),然后按1展开所有核心。一眼就能看出是单核打满还是多核均衡。如果是单核打满,多半是中断不均衡或者有单线程瓶颈。

嗯,CPU瓶颈定位这块,说白了就是四个字——望闻问切。望,看使用率和load;闻,听上下文切换和中断;问,查进程状态和锁竞争;切,用perf等工具深挖热点。把这套流程走熟了,大部分CPU问题都能快速定位。

想要更多资料,联系可可