Linux 内核进程调度器深度实战:从 CFS 红黑树到 EEVDF、实时调度类、cgroups v2 CPU 控制器与生产调优的完全工程指南
操作系统调度器是内核中最核心的组件之一——它决定了哪个线程在何时、哪个 CPU 核上执行。从早期的 O(n) 调度器到 O(1) 调度器,再到完全公平调度器 CFS,直至 Linux 6.6 引入的 EEVDF(Earliest Eligible Virtual Deadline First),Linux 调度器经历了四次重大架构变革。本文将从调度器基本原理出发,深入剖析 CFS 的 vruntime 机制与红黑树实现、EEVDD 算法的革命性改进、实时调度类(SCHED_FIFO/RR/DEADLINE)、cgroups v2 CPU 控制器、NUMA 负载均衡、内核抢占模型、上下文切换开销优化,并给出生产环境下的调优策略与监控方案。
1. 调度器演进简史
Linux 调度器的演进史就是一部"追求公平与效率平衡"的历史:
- O(n) 调度器(Linux 2.4):遍历所有可运行进程选择时间片最大的进程执行,时间复杂度 O(n),在进程数增长时性能急剧下降,SMP 支持原始。
- O(1) 调度器(Linux 2.6.0 ~ 2.6.22):引入 active/expired 两个优先级数组和 140 级优先级位图,选择进程时间复杂度 O(1),但交互进程识别启发式算法复杂且易被"欺骗"。
- CFS(Completely Fair Scheduler,Linux 2.6.23 ~ 6.5):由 Ingo Molnár 提出,核心思想是维护每个进程的 vruntime(虚拟运行时间),使用红黑树选择 vruntime 最小的进程运行,实现数学意义上的"完全公平"。
- EEVDF(Earliest Eligible Virtual Deadline First,Linux 6.6+ 默认):Mel Gorman 等人推动的替代方案,保留 vruntime 的一致性保证,通过引入 deadline 概念在 O(1) 时间内完成调度决策,同时解决了 CFS 在负载变化时的延迟波动问题。
CFS 的核心哲学极其优雅:不使用传统时间片,而是追踪每个进程已获得的 CPU 时间,每次选择累计运行时间最少的进程。这等价于让所有可运行进程"赛跑",落后的进程被优先调度,最终所有进程趋于相同的 vruntime。
2. CFS 核心原理:vruntime 与红黑树
2.1 vruntime 的权重计算
vruntime(虚拟运行时间)是 CFS 的命脉。每个进程的 vruntime 递增速度与其实际运行时间的关系由进程权重决定:
// 内核源码:kernel/sched/fair.c
static void update_curr(struct cfs_rq *cfs_rq)
{
struct sched_entity *curr = cfs_rq->curr;
u64 now = rq_clock_task(rq_of(cfs_rq));
u64 delta_exec;
delta_exec = now - curr->exec_start;
curr->exec_start = now;
curr->

发表评论 取消回复