4. IO 调度器发展史:从 CFQ 到 Deadline、NOOP,再到多队列时代
IO 调度器的演进史,本质上是存储硬件性能与软件栈之间不断博弈、消除瓶颈的历史。从机械硬盘时代到 NVMe SSD 时代,调度器的设计哲学经历了从“公平排队”到“最小延迟”,再到“零干预”和“多队列并行”的深刻转变。理解这段历史,是掌握现代调度器参数调优的前提。
4.1 机械硬盘时代:CFQ 与 Deadline 的统治
在机械硬盘(HDD)时代,IO 调度的核心矛盾是:寻道延迟。磁头在盘片上移动寻找数据位置,一次寻道耗时约 5-10ms,远高于数据传输时间。调度器的首要任务是将随机 IO 合并为顺序 IO,减少磁头移动。
4.1.1 CFQ(完全公平排队)
CFQ 是 Linux 内核 2.6 时代默认的 IO 调度器,其设计哲学是公平性。它为每个进程分配一个时间片,在时间片内,该进程的 IO 请求被优先处理。CFQ 通过复杂的排队和合并算法,试图让所有进程获得大致相等的磁盘带宽。
- 优点: 多进程并发场景下公平性好,能有效防止单个进程饿死。
- 缺点: 延迟不可控,上下文切换开销大,对 SSD 的随机 IO 性能提升有限。
- 适用场景: 传统的数据库服务器、文件服务器等混合负载场景。
4.1.2 Deadline(截止时间)
Deadline 调度器放弃了 CFQ 的完全公平,转而追求延迟确定性。它为每个 IO 请求设置一个截止时间(默认读 500ms,写 5s),并维护读、写两个 FIFO 队列。当有请求即将超时时,Deadline 会优先处理该请求,从而保证最坏情况下的响应时间。
- 优点: 读延迟低,写操作不会长时间阻塞读操作,适合对响应时间敏感的应用。
- 缺点: 公平性不如 CFQ,写操作可能被读操作频繁抢占。
- 适用场景: 实时数据库、Web 服务器、视频监控等对延迟有严格要求的场景。
slice_idle、fifo_expire 等参数,以平衡公平性与延迟。这些参数在 NVMe SSD 上已基本失效。
4.2 早期 SSD 时代:NOOP 的崛起
当 SATA SSD 开始普及时,其随机 IO 性能(约 10-50K IOPS)远超 HDD,但寻道时间几乎为零。此时,CFQ 和 Deadline 的复杂合并与排序逻辑反而成为性能瓶颈。NOOP(No Operation)调度器应运而生。
NOOP 的核心思想是“什么都不做”。它只维护一个简单的 FIFO 队列,将 IO 请求直接传递给底层驱动,不做任何合并或排序。它假设硬件(SSD 控制器)自己会处理请求的优化。
- 优点: 开销极低,延迟最小,适合纯随机 IO 场景。
- 缺点: 无法处理写放大问题,对顺序 IO 没有优化。
- 适用场景: 早期的 SATA SSD、虚拟化环境(宿主机层面)。
none 调度器取代。
4.3 多队列时代:blk-mq 与调度器重构
NVMe SSD 的出现,将 IOPS 推高至百万级别,单队列的 IO 栈成为瓶颈。Linux 内核 3.13 引入了 blk-mq(Block Multi-Queue) 框架,彻底重构了 IO 路径。blk-mq 将单队列拆分为多个软件队列(Software Queue)和硬件队列(Hardware Queue),实现了 CPU 核心与 NVMe 队列的直接映射,消除了锁竞争。
在 blk-mq 框架下,传统的 CFQ、Deadline、NOOP 被重新设计为 mq-deadline、bfq(Budget Fair Queueing,CFQ 的替代者)和 none(NOOP 的替代者)。
4.3.1 多队列架构对比
| 特性 | 单队列(传统) | 多队列(blk-mq) |
|---|---|---|
| 队列数量 | 1 个全局队列 | 多个软件队列 + 多个硬件队列 |
| 锁竞争 | 严重(单锁保护全局队列) | 极低(每个队列独立锁) |
| CPU 亲和性 | 差(请求可能被任意 CPU 处理) | 好(请求绑定到特定 CPU 和硬件队列) |
| 典型调度器 | CFQ, Deadline, NOOP | mq-deadline, bfq, none |
| 适用硬件 | HDD, SATA SSD | NVMe SSD, 高性能 SATA SSD |
4.3.2 现代调度器选择
- none: 默认调度器,零开销,适合绝大多数 NVMe SSD 场景。
- mq-deadline: 当需要保证读延迟上限时使用,例如数据库日志盘。
- bfq: 桌面环境或交互式应用,提供比 mq-deadline 更好的公平性。
4.4 调度器演进全景图
下图展示了从 HDD 到 NVMe SSD 时代,IO 调度器架构的演进路径。注意观察队列结构从单点到多点的变化,以及调度器角色从“主动控制”到“被动协调”的转变。
4.5 总结:调度器选择的黄金法则
在 NVMe SSD 场景下,调度器的选择已经变得非常简单。以下是基于性能测试和生产经验的推荐法则:
- 默认选择
none: 对于 99% 的 NVMe SSD 场景,none调度器能提供最低的延迟和最高的吞吐量。 - 特殊场景选择
mq-deadline: 当应用对读延迟有严格上限要求(如数据库 WAL 日志),且无法容忍偶尔的延迟尖刺时,使用mq-deadline并调整fifo_expire_read参数。 - 避免使用
bfq: 除非是桌面环境或需要精细的 IO 带宽控制,否则bfq在 NVMe SSD 上的额外开销通常不值得。
none 调度器相比 mq-deadline 在 4K 随机读场景下,延迟降低约 5-8%,吞吐量提升约 3-5%。在 QD=1 时,none 的延迟优势更为明显。