运维排查中遇到服务器卡顿,很多人的第一反应是查看 CPU 使用率。但真正经验丰富的工程师都知道,上下文切换频率往往比 CPU 利用率更能暴露系统瓶颈。而查看这一指标,最趁手的工具莫过于 vmstat——无需额外安装,一行命令就能将关键数据呈现在你面前。

直接运行 vmstat 1 就能看到 cs 值
无需安装软件包,也不需要 root 权限,vmstat 是绝大多数 Linux 发行版默认预装的性能分析工具。执行 vmstat 1 后,输出信息中第三行(system 模块)最右侧的 cs 列显示的就是「每秒上下文切换次数」——它并非瞬时值,而是本次采样周期(1 秒)内的平均速率。
不少初学者容易在这里踩坑:以为 vmstat -S M 或 vmstat -S K 能改变 cs 的单位,实际上这两个参数仅影响内存列(如 free、buff),对 cs、in 这类计数字段完全没有影响。它们的单位始终是「次/秒」,无需额外换算。
- 系统刚启动时,
cs短暂跃升至 5k–8k 属于正常现象——例如 systemd 拉起服务、日志刷盘等操作都会引发一波上下文切换。 - 空闲系统的典型参考范围:1000–1500 /秒;如果持续超过 5000 /秒,就需要引起警惕了。
- 切勿仅凭单次输出就匆忙下结论——建议至少观察 10 秒以上,重点识别是否存在脉冲式飙升(比如周期性冲到 20k+ 后又回落),这种模式通常指向某些定时任务或中断抖动。
cs 值偏高但找不到根因?必须联动分析 r、b、in
单独看到 cs=12000 几乎无法说明问题,真正有价值的是这四列的组合关系,它能直接告诉你上下文切换的“性质”:
r > CPU 核数(例如 4 核机器上r ≥ 5)并且cs也很高 → 说明 CPU 资源竞争激烈,大量属于非自愿切换(nvcswch/s主导),进程被调度器强制赶下 CPU。b > 0且cs中等偏高 → 进程卡在不可中断睡眠状态(常见于磁盘 I/O、锁等待),频繁挂起与唤醒,这种情况下自愿切换(cswch/s)占主导地位。in与cs同步飙升(比如都从 300 跃升到 9000)→ 这是典型的中断风暴,可能由网卡软中断、定时器或 NVMe 驱动异常引发。cs偏高但us和sy都偏低 → 上下文切换并非因计算密集引起,而是进程在等待资源(锁、网络、磁盘),此时%wa或bi/bo往往也居高不下。
为什么 vmstat 的 cs 和 pidstat -w 加起来对不上
这个问题几乎每个深入做过性能分析的工程师都会遇到。原因其实很简单:vmstat 统计的是内核全局视角的上下文切换总数,它包含三类开销:
- 进程/线程级切换(用户态任务之间的切换)
- 硬件中断处理时的上下文保存与恢复(例如网卡收包触发的
eth0中断) - 软中断上下文切换(如
ksoftirqd处理网络协议栈、定时器)
而 pidstat -w 只抓取每个进程的 cswch/s(自愿切换)和 nvcswch/s(非自愿切换),它并不统计中断相关的部分。因此 vmstat cs 一定 ≥ 所有进程 cswch/s + nvcswch/s 的总和——这不是 bug,而是设计如此,明白了这个原理就不会再感到困惑了。
举个例子:如果 cs=6000 且 in=5800,那么其中大约 5800 次切换与你的应用进程无关,纯粹是中断处理带来的开销。
别被 cs 数值带偏,真正的问题往往藏在 pidstat -w 里
vmstat 的作用就像体检报告中的血常规——它告诉你“存在异常”,但想要定位“是谁导致的”以及“为什么切换”,必须借助 pidstat -w 这把手术刀:
- 首次运行
pidstat -w 1输出的是累计值,第二次才开始计算增量速率,因此务必连续观察两轮以上,否则第一行数据可能会误导你。 cswch/s偏高 +nvcswch/s≈ 0 → 进程主动让出 CPU,此时可以使用strace -p PID -e trace=epoll_wait,read,futex检查它卡在哪些系统调用上。nvcswch/s偏高 → 调度器强制抢占,应优先排查是否存在 rogue 实时进程(用ps -eo pid,cls,rtprio,ni --sort=-rtprio扫描一遍),或者 Java GC 过于频繁、线程数远超 CPU 核数。- 进程状态为
D(不可中断睡眠)时,pidstat -w完全不会显示它——此时需使用ps -o pid,comm,state,wchan -p PID查看它卡在哪个内核函数中。
说到底,真正困难的不是看到 cs 偏高,而是分清它究竟是症状还是病因。vmstat 是筛子,pidstat 才是手术刀。只有将两者配合使用,才能把系统问题的本质真正挖掘出来。
