Linux 进程调度器全景:CFS、实时调度类与调度策略对比
在深入 Nginx 吞吐量调优之前,必须理解 Linux 进程调度器的完整架构。调度器决定了 CPU 时间如何在多个进程之间分配,直接影响 Nginx 这类网络密集型服务的响应延迟与并发处理能力。本章从调度器整体框架出发,对比 CFS、实时调度类以及三种核心调度策略(SCHED_OTHER、SCHED_FIFO、SCHED_RR),为后续参数调优奠定理论基础。
调度器整体架构
Linux 内核采用模块化调度框架,核心调度代码(kernel/sched/core.c)通过统一接口调用不同的调度类。每个调度类实现自己的就绪队列与调度算法,内核根据进程的调度策略选择对应的调度类。
- stop_sched_class — 最高优先级,用于停止 CPU 等特殊任务
- dl_sched_class — Deadline 调度类,用于实时截止期限任务
- rt_sched_class — 实时调度类,支持 SCHED_FIFO 和 SCHED_RR
- fair_sched_class — 完全公平调度类(CFS),对应 SCHED_OTHER、SCHED_BATCH、SCHED_IDLE
- idle_sched_class — 空闲调度类,CPU 无任务时运行
完全公平调度器(CFS)
CFS 是 Linux 默认调度器,对应 SCHED_OTHER 策略。其核心设计理念是“理想公平”:假设存在一个完全公平的多任务 CPU,每个任务获得 1/n 的 CPU 时间。CFS 通过虚拟运行时间(vruntime)实现这一目标。
| CFS 核心概念 | 说明 |
|---|---|
| vruntime | 虚拟运行时间,记录进程实际消耗的 CPU 时间(经优先级加权)。CFS 总是选择 vruntime 最小的进程运行。 |
| 红黑树 | 就绪队列以 vruntime 为键值组织成红黑树,最左节点即 vruntime 最小的进程。 |
| 调度延迟 | 保证每个可运行进程在给定时间窗口内至少获得一次 CPU 时间。 |
| 时间片 | CFS 没有固定时间片,而是根据可运行进程数量动态计算:时间片 = 调度延迟 / 进程数。 |
| nice 值 | 权重因子,范围 -20~19,值越小权重越高,vruntime 增长越慢,获得更多 CPU 时间。 |
sched_latency_ns(调度延迟)和 min_granularity_ns(最小粒度),可以控制 Nginx 进程的时间片大小,影响吞吐量与延迟的平衡。
实时调度类(RT)
实时调度类用于对响应时间有严格要求的任务,支持两种调度策略:SCHED_FIFO 和 SCHED_RR。实时进程的优先级范围是 0~99(数值越大优先级越高),始终高于普通进程(nice 值映射到 100~139 优先级)。
SCHED_FIFO(先进先出)
- 没有时间片限制,一旦获得 CPU,除非主动让出(如 sleep、等待 I/O)或被更高优先级进程抢占,否则一直运行。
- 适用于需要极低延迟且执行时间短的任务,如中断处理线程。
- 风险: 如果 FIFO 进程进入死循环,会永久阻塞所有低优先级进程,包括系统关键服务。
SCHED_RR(轮转)
- 在 FIFO 基础上增加了时间片轮转机制。同一优先级的 RR 进程按时间片轮流执行。
- 时间片长度由内核参数
sched_rr_timeslice_ms控制(默认 100ms)。 - 适用于需要公平轮转的实时任务,如多媒体处理。
三种调度策略对比
| 特性 | SCHED_OTHER (CFS) | SCHED_FIFO | SCHED_RR |
|---|---|---|---|
| 调度类 | fair_sched_class | rt_sched_class | rt_sched_class |
| 优先级范围 | 100~139(nice -20~19) | 0~99 | 0~99 |
| 时间片 | 动态计算(基于调度延迟和进程数) | 无时间片(运行直到主动让出) | 固定时间片(默认 100ms) |
| 抢占条件 | 更高优先级进程就绪,或 vruntime 差值超过阈值 | 更高优先级 FIFO/RR 进程就绪 | 更高优先级进程就绪,或时间片耗尽 |
| 适用场景 | 通用服务器、Web 服务、数据库 | 硬实时、中断处理、低延迟控制 | 软实时、多媒体、周期性任务 |
| 对 Nginx 的适用性 | ✅ 默认推荐,公平且稳定 | ⚠️ 高风险,仅特殊场景 | ⚠️ 中等风险,需严格测试 |
调度策略的查看与设置
在 Linux 系统中,可以使用 chrt 命令查看和修改进程的调度策略与优先级。
# 查看 Nginx 工作进程的调度策略
chrt -p $(pgrep -f 'nginx: worker')
# 将 Nginx 工作进程设置为 SCHED_FIFO,优先级 10
chrt -f -p 10 $(pgrep -f 'nginx: worker')
# 将 Nginx 工作进程设置为 SCHED_RR,优先级 10
chrt -r -p 10 $(pgrep -f 'nginx: worker')
# 查看所有进程的调度策略
ps -eo pid,comm,policy,rtprio,ni | grep nginx
- policy — 调度策略标识:TS(SCHED_OTHER)、FF(SCHED_FIFO)、RR(SCHED_RR)
- rtprio — 实时优先级(仅对 FF/RR 有效)
- ni — nice 值(仅对 TS 有效)
调度器参数对 Nginx 的影响路径
理解调度器全景后,需要明确调度参数如何最终影响 Nginx 的吞吐量:
- CFS 调度延迟(sched_latency_ns) — 增大该值使每个 Nginx 工作进程获得更长的时间片,减少上下文切换次数,提升吞吐量;但会增加其他进程的调度延迟。
- 最小粒度(min_granularity_ns) — 控制进程被抢占的最小执行时间。减小该值使调度更频繁,提升交互性但降低吞吐量。
- nice 值 — 降低 Nginx 进程的 nice 值(提高优先级),使其在竞争 CPU 时获得更多时间片。
- 实时优先级 — 将 Nginx 关键线程提升为实时优先级,可显著降低延迟,但必须谨慎使用。
小结
Linux 调度器通过模块化架构将 CFS、实时调度类和空闲调度类有机整合。对于 Nginx 调优而言,SCHED_OTHER(CFS) 是默认且最安全的选择,通过调整 CFS 内核参数(调度延迟、最小粒度)和进程 nice 值,可以在吞吐量与延迟之间找到最佳平衡点。实时调度策略(SCHED_FIFO/SCHED_RR)虽然能提供极低延迟,但风险较高,仅在充分隔离的环境中谨慎使用。