3. I/O调度器原理

I/O 调度器位于通用块层与块设备驱动之间,其核心职责是对下发的 BIO(块 I/O 请求)进行排队、合并与排序,以优化磁盘寻道时间、提高吞吐量或降低延迟。Linux 内核支持多种调度器,每种调度器在设计哲学与适用场景上存在显著差异。本章将深入剖析 CFQ、Deadline、NOOP、Kyber 与 BFQ 五种主流调度器的工作机制与选型依据。

3.1 I/O 调度器在存储栈中的位置

下图展示了 I/O 调度器在 Linux 块 I/O 栈中的层级关系:

I/O 调度器在块设备栈中的位置 I/O 调度器在 Linux 块设备栈中的位置 VFS / 系统调用层 文件系统层 (ext4/xfs/btrfs) 通用块层 (BIO 提交) I/O 调度器 (CFQ/Deadline/NOOP/Kyber/BFQ) 请求合并、排序、分发 块设备驱动层 物理设备 (HDD/SSD/NVMe) 关键位置 I/O 调度器是通用块层 与设备驱动之间的 核心排队与分发组件
调度器选型原则: 对于传统 HDD,调度器通过减少寻道次数提升吞吐量;对于 NVMe SSD,调度器应尽量降低软件开销,避免成为性能瓶颈。

3.2 CFQ (Completely Fair Queuing)

CFQ 是 Linux 内核长期以来的默认 I/O 调度器,其设计理念源自 CPU 调度中的完全公平队列算法。CFQ 为每个发起 I/O 的进程分配独立的时间片与请求队列,通过轮转调度保证所有进程获得近似公平的 I/O 带宽。

3.2.1 工作机制

  • 进程队列隔离: 每个进程拥有独立的请求队列,进程间的 I/O 请求不会相互干扰。
  • 时间片轮转: 调度器按时间片轮转方式依次服务每个进程队列,每个时间片内尽量连续处理同一进程的请求。
  • 请求合并与排序: 在队列内部,CFQ 对相邻扇区请求进行合并,并按扇区号进行排序,减少磁盘寻道。
  • 优先级支持: 通过 ionice 工具可设置进程的 I/O 优先级(实时、尽力、空闲),CFQ 据此分配不同的时间片长度。

3.2.2 适用场景

场景 评价
传统 HDD 多进程负载 公平性好,吞吐量稳定
桌面系统(混合负载) 交互式进程响应较好
NVMe SSD 高并发场景 调度开销过大,不推荐
数据库等延迟敏感应用 公平性导致写延迟抖动
注意: 自 Linux 5.0 起,CFQ 已被移除,由 BFQ 和 Kyber 替代。在较老内核(4.x 及之前)中仍可使用。

3.3 Deadline 调度器

Deadline 调度器以请求的截止时间(deadline)为核心调度依据,旨在保证每个 I/O 请求在可接受的延迟范围内得到服务,避免请求“饿死”。

3.3.1 工作机制

Deadline 调度器工作流程 Deadline 调度器工作流程 BIO 请求输入 排序队列 (按扇区) 红黑树组织 分发队列 (FIFO) 按 deadline 排序 下发至驱动 调度决策逻辑 优先检查分发队列头部是否超 deadline → 超时则立即调度 否则从排序队列按扇区顺序取出请求
  • 双队列结构: 维护一个按扇区排序的排序队列(红黑树)和一个按 deadline 排序的分发队列(FIFO)。
  • 截止时间机制: 每个请求被赋予一个 deadline(读请求通常为 500ms,写请求为 5s),超时请求被优先处理。
  • 读写分离: 读请求具有更短的 deadline,确保读操作的低延迟,避免写操作阻塞读操作。
  • 批量处理: 在未超时的情况下,按扇区顺序批量处理请求,兼顾吞吐量。

3.3.2 适用场景

场景 评价
数据库服务器 读延迟低,写操作不阻塞读
虚拟化宿主机 多虚拟机 I/O 延迟可控
实时音视频处理 保证关键请求的及时响应
纯写负载(日志) 写 deadline 较长,效果一般

3.4 NOOP 调度器

NOOP(No Operation)调度器是所有调度器中最简单的一种,它几乎不做任何调度决策,仅执行最基本的请求合并操作,然后将请求直接插入到驱动层的请求队列中。

3.4.1 工作机制

  • FIFO 队列: 请求按到达顺序放入一个 FIFO 队列,不做排序。
  • 相邻合并: 仅对相邻扇区的请求进行合并,减少中断次数。
  • 零调度开销: 不进行任何寻道优化或优先级调度,CPU 开销极低。

3.4.2 适用场景

场景 评价
NVMe SSD 无机械寻道,调度器反而增加延迟
硬件 RAID 卡 RAID 卡自身有调度逻辑,上层无需重复调度
UIO 或 DPDK 场景 用户态驱动直接管理 I/O,内核调度器越简单越好
虚拟化 Guest 内部 宿主机已做调度,Guest 内部使用 NOOP 减少嵌套
性能数据参考: 在 NVMe SSD 上,使用 NOOP 相比 CFQ 可降低 15%-30% 的 I/O 延迟,吞吐量提升 10%-20%。

3.5 Kyber 调度器

Kyber 是专为快速固态存储设备设计的一种轻量级调度器,它通过动态调整令牌分配来控制 I/O 延迟,无需复杂的队列管理。

3.5.1 工作机制

Kyber 调度器令牌控制模型 Kyber 调度器令牌控制模型 读令牌桶 目标延迟: 2ms 令牌数动态调整 写令牌桶 目标延迟: 10ms 令牌数动态调整 调度决策 有令牌 → 下发 无令牌 → 排队等待 延迟反馈:实际延迟 > 目标延迟 → 减少令牌数 核心思想:基于延迟反馈的令牌桶控制 当设备实际延迟低于目标延迟时增加令牌数(提高并发),反之减少令牌数(降低负载)
  • 读写分离令牌桶: 为读和写分别维护独立的令牌桶,读令牌桶的目标延迟更短。
  • 动态令牌调整: 根据设备实际 I/O 延迟与目标延迟的偏差,动态调整令牌发放速率。
  • 无排序开销: 不维护排序队列,请求按到达顺序处理,适合随机访问性能优异的 SSD。
  • 低 CPU 占用: 调度算法简单,CPU 开销远低于 CFQ 和 BFQ。

3.5.2 适用场景

场景 评价
NVMe SSD 云主机 延迟可控,CPU 开销低
延迟敏感型应用 通过目标延迟保证 QoS
多租户存储系统 读写隔离,避免相互干扰
传统 HDD 无寻道优化,不推荐

3.6 BFQ (Budget Fair Queuing)

BFQ 是 CFQ 的现代替代品,基于“预算”(budget)概念实现更精细的 I/O 带宽分配。BFQ 不仅考虑时间片,还考虑每次 I/O 操作传输的数据量。

3.6.1 工作机制

  • 预算分配: 每个进程队列被分配一个预算(以扇区数计量),预算用完后切换到下一个队列。
  • 低延迟模式: 对交互式进程(如文本编辑器)的 I/O 请求进行快速响应,减少感知延迟。
  • 权重控制: 支持精细的权重设置,权重高的进程获得更多的预算和更频繁的调度机会。
  • 请求预取: 根据进程的 I/O 模式进行预取优化,提升顺序读性能。

3.6.2 适用场景

场景 评价
桌面系统(多媒体、办公) 交互体验优秀,系统不卡顿
Android 设备 Google 推荐,低延迟模式适合移动端
多进程混合负载 公平性优于 CFQ,延迟更低
高吞吐服务器 调度开销较大,可能成为瓶颈
BFQ 与 CFQ 对比: BFQ 在公平性上更精确,延迟控制更好,但 CPU 开销比 CFQ 高约 10%-20%。在桌面和移动场景中,这种开销是值得的。

3.7 五种调度器对比总结

调度器 核心机制 延迟控制 公平性 CPU 开销 推荐设备
CFQ 进程时间片轮转 中等 高 高 HDD(已废弃)
Deadline 截止时间 + 双队列 高(读优先) 中等 中 HDD / SATA SSD
NOOP FIFO + 合并 低 低 极低 NVMe / RAID
Kyber 令牌桶 + 延迟反馈 高(可配置) 中等 低 NVMe SSD
BFQ 预算分配 + 权重 高(低延迟模式) 极高 高 桌面 / Android

3.8 调度器切换与运行时调整

在 Linux 系统中,可以通过以下方式查看和切换 I/O 调度器:

# 查看当前系统支持的调度器及当前生效的调度器
cat /sys/block/sda/queue/scheduler

# 输出示例:[mq-deadline] kyber bfq none

# 临时切换调度器(重启后失效)
echo kyber > /sys/block/sda/queue/scheduler

# 永久切换(通过内核启动参数)
# 在 GRUB 配置中添加: elevator=kyber

# 查看当前调度器参数
cat /sys/block/sda/queue/iosched/
内核版本差异: 自 Linux 5.0 起,多队列块层(blk-mq)成为默认配置,调度器名称前通常带有 "mq-" 前缀,如 mq-deadline、none(对应 NOOP)。CFQ 已被移除,BFQ 和 Kyber 作为替代方案。

3.9 选型决策树

I/O 调度器选型决策树 I/O 调度器选型决策树 设备类型? HDD / SATA SSD Deadline BFQ(桌面) NVMe SSD Kyber NOOP 选型建议 HDD 优先考虑 Deadline(延迟敏感)或 BFQ(公平性优先) NVMe 优先考虑 Kyber(延迟可控)或 NOOP(最低开销)

在实际工程中,建议通过 fio 等工具对目标负载进行基准测试,结合延迟分布(P99/P999)和吞吐量指标,选择最适合当前硬件与业务模型的调度器。对于大多数现代 NVMe SSD 场景,Kyber 是兼顾延迟与吞吐量的最佳选择。