CPU 与调度60 条

CFS 调度器与 vruntime

完全公平调度(CFS)以 vruntime 排序选择任务:权重(由 nice 映射)影响 vruntime 增速,从而决定 CPU 分配比例。

CFS 调度器是什么

CFS 是完全公平调度器,Linux 从 2.6.23 起作为普通进程的默认调度策略。它给每个可运行任务维护一个 vruntime,即按权重折算后的累计运行时间;调度时总是挑选 vruntime 最小的任务执行,红黑树就是这个选择过程的数据结构。权重由 nice 值映射而来,nice 每相差一级权重约差 1.25 倍,因此「公平」指的是按权重比例分配 CPU 时间,而不是每个任务平均分到相同的时间片。

基本信息

核心量vruntime,按权重折算的累计运行时间
选择结构红黑树,取 vruntime 最小的任务
权重来源nice 值映射的权重表,nice 每级权重约差 1.25 倍
nice 范围-20(最高优先级)到 19(最低),默认 0
观测入口/proc/sched_debug(需权限)、/proc/<pid>/sched、pidstat
版本变化较新内核引入 EEVDF 调度模型,具体行为以所用内核版本为准

典型使用场景

  • 理解 CPU 竞争:多个任务争抢同一颗核时,按 nice 比例分配才能解释观测结果
  • 调优批处理任务:把后台任务降 nice,让在线业务优先获得 CPU
  • 排查不公平现象:预期按比例分配却严重偏斜时,检查 cgroup 权重与 CPU 亲和性
  • 容器限额规划:cgroup 的 cpu.weight 与 nice 是两套权重体系,需要理清各自作用
  • 性能分析:结合 /proc/<进程>/sched 看实际运行时间与切换情况

观察与调整

观察与调整
ps -eo pid,ni,pri,pcpu,comm --sort=-pcpu | head    # 查看 nice 与实际占用
nice -n 10 tar czf backup.tar.gz /data             # 以较低优先级运行
renice -n 5 -p 12345                               # 调整已运行进程的 nice
cat /proc/sched_debug | head -30                   # 需权限,查看调度实体信息
cat /proc/12345/sched | grep -E 'nr_switches|se.sum_exec'   # 单进程调度统计
cat /sys/fs/cgroup/cpu.weight 2>/dev/null          # cgroup v2 权重

权重与时间分配

概念含义判读要点
vruntime按权重折算的累计运行时间调度器总选最小者,体现比例而非绝对优先级
nice静态优先级,范围 -20 到 19每级权重约差 1.25 倍,实际是比例关系
cgroup 权重cgroup v2 的 cpu.weight作用于分组之间,与进程 nice 是两套体系
切换统计/proc/<pid>/sched 中的切换计数结合运行时间判断任务实际得到的份额
nice 调整的是 CPU 分配比例,不是让任务彻底停摆:即使把 nice 提到 19,在系统不太忙时它依然能跑满 CPU。真正需要硬性隔离时应使用 CPU 亲和性绑定或 cgroup 配额。
留意内核版本差异:较新内核引入了新的调度模型,公平性的具体实现与老版本 CFS 不完全一致。跨版本对比调优结论前,先确认两端内核的行为是否可比。

易错点

  • 把 nice 当绝对优先级:它是权重比例,空闲系统上低优先级任务照样能占满 CPU
  • 忽略 cgroup 权重与 nice 的叠加:容器场景下两层权重共同决定实际份额
  • 仅凭 vmstat 与 top 判断公平性:需要结合进程级运行时间统计才能得出结论
  • 在跨内核版本的机器间照搬调优结论:调度模型实现有差异,行为不可直接类比
  • 用降 nice 代替资源隔离:关键业务与批处理混布时应使用亲和性或配额做硬隔离

数据来源与参考

  • Linux 内核 Documentation/scheduler/sched-design-CFS.rst
  • Linux 内核源码 kernel/sched/fair.c
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌