空闲系统下cs通常在1000–1500次/秒以内;持续超5000次/秒需警惕,但须结合业务基线判断,且必须联动r、b、in三列分析:r长期大于cpu核数指向非自愿切换,b升高指向i/o或锁等待引发的自愿切换,in与cs同步飙升提示中断风暴。

vmstat 的 cs 列怎么看才算高
空闲系统下 cs 通常在 1000–1500 次/秒以内;持续超过 5000 次/秒就要警惕,但这不是硬阈值——得结合你业务的基线来判断。比如压测时 cs 从 2000 翻到 6000,哪怕没超 5000,也值得查。
单独看 cs 没意义,必须联动三列:
-
r(就绪队列长度)长期大于 CPU 核数 → 多任务抢 CPU,非自愿切换主导 -
b(阻塞进程数)同步升高 → I/O 延迟或锁争用,自愿切换变多 -
in(每秒中断数)和cs同步飙升 → 中断风暴,比如网卡软中断过载
执行 vmstat 1 后,别只盯着第一行(那是启动以来平均值),从第二行开始才是实时数据。
为什么 vmstat cs 和 pidstat 总和对不上
vmstat 的 cs 是内核全局计数器,它包含三类事件:
- 进程/线程级上下文切换(
pidstat -w统计的那部分) - 硬件中断上下文切换(如磁盘、网卡触发的中断处理)
- 软中断上下文切换(如网络协议栈、定时器 softirq)
而 pidstat -w 只统计前一类,且只覆盖用户态任务,不包括内核线程和中断上下文。所以 vmstat cs 一定 ≥ 所有进程 cswch/s + nvcswch/s 的总和——差值就是中断相关切换。
这解释了常见现象:某 Java 进程 nvcswch/s 很低,但 vmstat cs 却很高 → 八成是网卡收包太猛,触发大量软中断。
pidstat -w 输出里 cswch 和 nvcswch 怎么区分根因
cswch/s(自愿切换)高,说明进程主动让出 CPU,常见于:
- 等待磁盘 I/O(
top看%wa是否高) - 调用
sleep()、read()、poll()等阻塞系统调用 - Java 应用中频繁加锁失败后
Thread.yield()或进入WAITING状态
nvcswch/s(非自愿切换)高,则指向调度器强制干预:
- CPU 时间片耗尽,被抢占(
r高 +us/sy高) - 高优先级实时进程(
SCHED_FIFO)反复打断普通进程 - 内核线程(如
ksoftirqd)密集运行,挤占时间片
例如一个 Python 进程 cswch/s = 800、nvcswch/s = 20,基本可锁定是日志刷盘或数据库查询慢;反过来若 nvcswch/s = 5000,就得先查 ps -eo pid,cls,rtprio,ni --sort=-rtprio 看有没有 rogue 实时进程。
实际排查时最容易忽略的两个点
第一,vmstat 默认输出的第一行是系统启动以来的平均值,不是当前负载。新手常误以为 cs=1200 就安全,其实后面几行可能已飙到 15000 ——务必等两秒再看第二行起的数据。
第二,pidstat -w 默认只显示活跃进程,如果某个进程刚启动又快速退出(比如短命的 cron 任务或容器健康检查),它根本不会出现在输出里,但这些“瞬态进程”可能贡献了大量 cs。这时候得配合 perf record -e context-switches -a sleep 5 抓现场,再用 perf script 看切换发生在哪个函数路径上。











