超过1000次/秒的上下文切换(cs)是多数稳定服务出现调度压力的临界信号;vmstat的cs列仅反映系统级总量,含进程、中断及软中断切换,无法定位具体进程或区分自愿/非自愿切换,须结合pidstat -w、r/b/in等指标综合判断。

超过 1000 次/秒的上下文切换(cs)就该警惕——这不是“高不高”的问题,而是多数稳定服务开始出现调度压力的临界信号;但单看这个数字没用,必须拆到进程级、分清自愿/非自愿,否则你永远在修表象。
vmstat 的 cs 列只告诉你“有没有事”,不告诉你“谁干的”
vmstat 1 输出里的 cs 是系统全局每秒上下文切换总次数,它包含:进程/线程切换、中断上下文、软中断上下文。这意味着:
-
cs高 ≠ 进程写得烂——可能是网卡每秒触发 5000 次软中断(in同步飙升),vmstat照样计入cs -
cs和pidstat -w的和永远对不上,因为后者只统计用户态进程的自愿/非自愿切换,不碰中断上下文 - 刚执行
vmstat 1时看到cs=8600,不代表持续高压——要连续观察 10 秒以上,看是否脉冲式跳变(如周期性冲到 20k+ 后回落) - 若
r > CPU 核数且cs > 5000,优先怀疑 CPU 竞争;若b > 0且cs中等,大概率是磁盘或锁卡住进程,导致反复挂起/唤醒
用 pidstat -w 定位高切换进程,但必须带采样间隔
pidstat -w 不加时间参数会立刻退出、无输出——这是新手最常卡住的地方。真正有用的命令是:
-
pidstat -w 1:每秒刷新,只显示cswch/s(自愿)和nvcswch/s(非自愿)非零的活跃进程 -
pidstat -w -p 1234 0.5:盯住某个 PID,半秒一采,适合抓短时抖动(比如 GC 触发瞬间) -
pidstat -w -t -p 1234 1:开启线程级统计(LWP),Java/Python 多线程场景必须加-t,否则进程级cswch/s可能被平均稀释
注意:pidstat 首次输出是累计值,第二次才开始算增量速率;老版本 sysstat(如 RHEL 7 自带的 10.1.5)不支持 -w 和 -t 同时生效,先跑 pidstat -V 确认版本 ≥ 11.0.0。
Linux AI 服务器 — 将 Linux 服务器转换为本地 AI 推理集群。使用 systemd、NVIDIA CUDA 实现无头 Linux AI,零 GUI 开销。
cswch/s 高但 %CPU 低?重点查 I/O 和锁
自愿切换(cswch/s)本质是进程主动让出 CPU,常见于等待资源就绪。典型表现:
-
cswch/s > 100且nvcswch/s ≈ 0:不是 CPU 不够,而是卡在某处——用strace -p PID -e trace=epoll_wait,read,write,futex看当前阻塞在哪类系统调用 - Java 应用中
cswch/s突增 +jstack显示大量java.lang.Thread.State: BLOCKED→ 锁粒度太细或 synchronized 争抢激烈 - 数据库连接池耗尽时,线程在
getConnection()上等待空闲连接,表现为条件变量等待,计入cswch/s - 进程状态为
D(不可中断睡眠)时,pidstat -w会完全不显示它——此时要用ps -o pid,comm,state,wchan -p PID查卡在哪个内核函数里
别信瞬时峰值,用 /proc/stat 算平滑速率
vmstat 和 pidstat 都是采样工具,容易被几秒毛刺干扰。真要判断长期趋势,直接读内核统计:
- 运行
grep ctxt /proc/stat,得到形如ctxt 123456789,这是系统启动以来的总切换次数 - 隔 30 秒再查一次,差值 ÷ 30 = 平均 cps,比实时工具更抗噪
- 如果 1 小时内增长 360 万次(即平均 1000/s),而业务 QPS 没变,说明底层有隐性资源争抢(比如日志刷盘频率突增、定时任务批量 fork)
真正难的不是查出 cs 高,而是区分它是症状还是病因——比如 nvcswch/s 高,到底是线程数远超 CPU 核数,还是 Java GC 线程频繁抢占,抑或内核调度器本身出了问题。这需要结合 mpstat -P ALL 1 看各核负载分布、perf record -e context-switches 抓切换现场,才能闭环。


















