CPU 是服务器上最容易被「冤枉」也最容易被「放过」的资源。明明top显示 CPU 才 30%应用却慢得不行——很可能是单核打满、IO 等待或者锁竞争在偷走时间。这一篇把 CPU 分析的四层工具讲透top看全局、mpstat看核心、pidstat看进程、perf看函数层层下钻直到找出真正的瓶颈。一、CPU 分析的四个层次排 CPU 问题最忌讳一上来就盯着top的进程榜。正确的思路是层层下钻层次工具回答什么问题系统概览top/uptime整体忙不忙、负载高不高每核视角mpstat -P ALL是所有核忙还是单核打满进程视角pidstat哪个进程、哪个线程在吃 CPU函数视角perf到底哪行代码、哪个系统调用在耗 CPU先看全局再看核心分布再看进程最后才用perf钻到函数。跳步容易误判。二、top先分清 us、sy、watop的第一行%Cpu(s)是最容易读错的地方。先把这几个字段记住字段含义高了说明什么us用户态 CPU 时间应用本身在算正常sy内核态 CPU 时间系统调用/中断多或内核开销大ni低优先级nice用户态手动调过 nice 的进程占的id空闲越低越忙wa等待 IO 的时间磁盘/网络是瓶颈hi硬中断设备中断多常见于网络/磁盘风暴si软中断网络收包处理多常见于高流量服务器st被虚拟化偷走的时间虚拟机被宿主机抢占越高越慢关键判断规则us高应用逻辑重去看代码热点。sy高系统调用频繁、上下文切换多去看vmstat的cs。wa高这不是 CPU 问题是 IO 问题去查磁盘见第 66 篇。si高软中断处理多多半是网络包量太大。st高你在虚拟机上被隔壁邻居抢了只能找云厂商。一个高频误区load average 高 ≠ CPU 忙uptime和top顶部的load average统计的是「运行队列 不可中断睡眠D 状态的进程数」的滑动平均。所以大量进程卡在 IOD 状态load 也会很高但 CPU 其实很闲。判断 CPU 是否真的紧张要看 load 是否由R状态贡献以及是否超过 CPU 核心数。用一行命令区分vmstat 1 3看r列运行队列和b列不可中断睡眠。r大才是 CPU 排队b大是 IO 在拖。三、mpstat每个核心的独立视角top默认显示的是所有核的平均使用率这会掩盖「单核打满」的问题。一个 16 核的机器一核 100%、其余空闲平均值只有 6.25%看起来一切正常。mpstat就是来解决这个的。mpstat属于sysstat包先装# Ubuntu / Debian sudo apt install sysstat -y # CentOS / Rocky sudo dnf install sysstat -y语法格式mpstat [选项] [间隔] [次数]常用参数参数说明-P ALL显示每个核心关键参数-P 0只看 0 号核1 5每秒采样共 5 次-u显示 CPU 使用率默认-I SUM显示中断统计示例与预期输出mpstat -P ALL 1 3预期输出Linux 5.15.0 (web01) 01/15/2026 _x86_64_ (4 CPU) 10:30:01 AM CPU %usr %nice %sys %iowait %irq %soft %steal %idle 10:30:02 AM all 6.25 0.00 1.50 0.25 0.00 0.25 0.00 91.75 10:30:02 AM 0 99.00 0.00 1.00 0.00 0.00 0.00 0.00 0.00 10:30:02 AM 1 0.00 0.00 0.50 0.00 0.00 1.00 0.00 98.50 10:30:02 AM 2 0.00 0.00 2.00 0.50 0.00 0.00 0.00 97.50 10:30:02 AM 3 0.00 0.00 1.00 0.50 0.00 0.00 0.00 98.00一眼看出问题all行看起来只用了 6%但0 号核 99% 打满。典型的单线程程序只吃一个核。这种问题只有mpstat -P ALL才能暴露。什么时候该怀疑单核瓶颈应用是单线程或单线程池跑在一个核上。应用有全局锁多线程也没法并行。中断亲和性设置把所有网卡中断都绑到一个核。单核打满时横向扩容进程数多实例往往比优化单进程更有效。四、pidstat定位到进程和线程知道是哪个核忙了还要知道是谁在忙。pidstat是sysstat里的进程级采样工具比top更适合做数据记录。语法格式pidstat [选项] [间隔] [次数]常用参数参数说明-uCPU 使用率默认-t显示线程级统计-p PID指定进程-d磁盘 IO 统计-r内存统计-w上下文切换统计示例与预期输出所有进程按 CPU 排序pidstat -u 1 3 | sort -k8 -nr | head看某进程内部的线程谁在吃 CPUpidstat -t -p 1234 1 3预期输出Average: UID TGID TID %usr %system %CPU CPU Command Average: 1000 1234 - 2.00 1.00 3.00 - java Average: 1000 - 1235 95.00 1.00 96.00 2 |__java Average: 1000 - 1236 0.50 0.20 0.70 1 |__javaTGID是进程号TID是线程号。一眼看出 1235 号线程吃了 96% CPU拿着它去jstack或gdb定位就够了。看上下文切换排查「CPU 不高但很慢」pidstat -w -p 1234 1 3Average: cswch/s nvcswch/s Command Average: 12500.00 850.00 javacswch/s自愿上下文切换进程主动让出如等锁、等 IOnvcswch/s非自愿切换时间片用完被抢占自愿切换极高通常是锁竞争或频繁 IO非自愿切换高说明 CPU 争抢激烈。五、perf钻到函数级前三层告诉你「哪个进程、哪个线程」perf告诉你「哪个函数」。它是 Linux 官方性能分析工具基于内核的 PMU性能监控单元采样。安装sudo apt install linux-tools-common linux-tools-$(uname -r) # Ubuntu sudo dnf install perf # CentOS/Rocky常用子命令命令作用perf top实时显示热点函数类似 top 但到函数级perf stat统计程序整体指标指令数、缓存命中perf record采样记录到文件perf report分析 record 生成的 perf.dataperf script把记录导出成文本供火焰图工具用示例与预期输出实时看系统热点函数sudo perf topOverhead Shared Object Symbol 35.20% libc-2.31.so [.] __memmove_avx_unaligned 18.40% [kernel] [k] __schedule 9.70% app [.] parse_json__memmove占 35%说明大量内存拷贝__schedule高说明调度频繁。这些线索直接指向优化方向。统计程序整体性能sudo perf stat ./app1,204,582,391 instructions # 0.85 insn per cycle 1,417,155,724 cycles 412,036,588 cache-references 88,201,004 cache-misses # 21.40% of all cache refs关键看两个IPCinsn per cycle和cache-misses 比例。IPC 1 说明 CPU 在等多为缓存未命中或依赖停顿cache-misses 高说明内存访问模式差。生成火焰图最常用# 采样 30 秒 sudo perf record -F 99 -a -g -- sleep 30 sudo perf script out.perf # 用 FlameGraph 工具生成 ./stackcollapse-perf.pl out.perf | ./flamegraph.pl flame.svg火焰图第 69 篇会专门讲这里先记住perf record -g是入口。六、⚠️ 常见错误只看平均值错过单核瓶颈。top的百分比是所有核平均单核打满会被稀释。用mpstat -P ALL。把 wa 高当成 CPU 问题。wa是「CPU 在等 IO」根因在磁盘/网络去查第 66 篇别死磕 CPU。load 高就加 CPU。如果 load 是被D状态IO 阻塞推高的加 CPU 没用。先用vmstat区分r和b。忽视 ststeal。云主机st高是被宿主机邻居抢资源优化自己没用要么换实例规格要么换可用区。perf 采样被内核限制。默认perf_event_paranoid可能禁止普通用户采样报Permission denied就加sudo或调sysctl kernel.perf_event_paranoid。sy 高就怪内核。sy高往往是应用频繁系统调用或锁竞争导致未必是内核本身的问题。七、原理探究上下文切换、中断与 CPU 缓存CPU 的速度比内存快两个数量级比磁盘快五六个数量级。理解 CPU 性能核心是理解「它在等什么」。上下文切换context switchCPU 核心只有一个多个进程/线程要轮着用。切换时要保存当前任务的寄存器、程序计数器、栈指针再加载下一个任务的——这一套动作本身就要花时间更糟的是会污染 CPU 缓存新任务的数据不在缓存里得重新从内存拉这就是cache miss。所以上下文切换次数vmstat的cs、pidstat -w过高CPU 大量时间花在「切换」而不是「干活」上。自愿切换多→ 等锁、等 IO非自愿切换多→ 被迫让出CPU 争抢。中断设备网卡、磁盘完成工作时会发中断通知 CPU。中断分两种硬中断hi设备直接打断 CPU处理要快、要短。软中断si硬中断的下半部延后处理。网络收包大量走软中断。高流量服务器si常年偏高很正常但如果si高到挤占业务 CPU就要上多队列网卡、开启 RPS/RSS、调中断亲和性来分摊。CPU 缓存层级现代 CPU 有三层缓存层级特点典型延迟L1每个核私有最小最快~1nsL2每个核私有~4nsL3多核共享~10ns内存所有核共享~100ns程序的数据局部性越好命中缓存越多CPU 利用率越高IPC 越大。perf stat的 cache-misses 就是看这个。优化数据结构和访问顺序有时比换更快的 CPU 更有效。一句话串起来CPU 忙 → 看us应用/sy内核CPU 不忙但慢 → 看waIO、steal虚拟化、上下文切换平均正常但应用慢 → 看单核mpstat -P ALL、看锁pidstat -w定位到进程后 →perf钻到函数八、CPU 排查速查表# 1. 整体概览 uptime top -bn1 | head -5 # 2. 每核分布 mpstat -P ALL 1 3 # 3. 找吃 CPU 的进程用户态 ps -eo pid,cmd,%cpu --sort-%cpu | head # 4. 找吃 CPU 的进程内核态/上下文切换 pidstat -w 1 3 # 5. 函数级热点 sudo perf top # 6. 程序整体性能 sudo perf stat -d ./app记住排查的主线全局 → 核心 → 进程 → 线程 → 函数一步一层别急着下结论。多数「CPU 高」的锅最后都落在单核瓶颈、锁竞争或 IO 等待上而不是真的 CPU 算不过来。