2、I/O调度器原理:CFQ、Deadline、NOOP、Kyber、BFQ调度器的工作机制与适用场景

Linux 块设备层中,I/O 调度器(I/O Scheduler)是位于通用块层与底层驱动之间的关键组件。其核心职责是对来自文件系统或直接 I/O 的请求进行排队、合并与排序,以优化磁盘寻道时间、降低延迟或保障公平性。不同的调度器在设计哲学上存在显著差异,理解其工作机制是进行存储性能调优的前提。

核心认知: 调度器的选择本质上是 吞吐量、延迟 与 公平性 三者之间的权衡。没有绝对最优的调度器,只有最适合当前负载场景的调度器。

2.1 I/O调度器在块设备栈中的位置

下图展示了 I/O 调度器在 Linux 存储栈中的位置。它接收来自通用块层的 bio 请求,经过调度与合并后,生成 request 结构体并传递给底层驱动。

I/O 调度器在 Linux 存储栈中的位置 用户空间 (应用程序 / 数据库) VFS / 文件系统层 通用块层 (bio 生成) I/O 调度器 (CFQ / Deadline / NOOP / Kyber / BFQ) 请求合并、排序、分发 块设备驱动层 (DMA / 中断处理) 物理存储设备 (SSD / HDD / NVMe)

2.2 五大调度器工作机制详解

2.2.1 CFQ (Completely Fair Queuing)

CFQ 是 Linux 内核中长期以来的默认调度器,其设计目标是 公平性。它为每个进程分配独立的 I/O 时间片,并在时间片内处理该进程的请求队列。CFQ 通过计算进程的 I/O 优先级和权重,确保所有进程都能获得合理的 I/O 带宽。

  • 工作机制: 维护多个内部队列(每个进程一个),通过时间片轮转调度。支持进程 I/O 优先级(ionice)。
  • 优点: 多进程环境下公平性好,能有效防止单个进程饿死其他进程。
  • 缺点: 延迟较高,不适合随机 I/O 密集场景;在高速 SSD 上调度开销占比过大。
  • 适用场景: 传统的机械硬盘(HDD)环境,尤其是桌面系统或通用服务器。

2.2.2 Deadline

Deadline 调度器以 延迟保障 为核心目标。它维护两个队列:一个按扇区排序(提高吞吐),另一个按请求过期时间排序(保障延迟)。每个请求被赋予一个截止时间(读请求通常为 500ms,写请求为 5s)。

  • 工作机制: 正常情况下按扇区顺序分发请求;当有请求即将超时时,立即切换到“截止时间”队列,优先处理超时请求。
  • 优点: 读请求延迟低,写请求不会无限阻塞;在数据库等延迟敏感场景表现优秀。
  • 缺点: 公平性不如 CFQ,写请求可能被读请求大幅抢占。
  • 适用场景: 数据库服务器、实时应用、混合读写负载。

2.2.3 NOOP (No Operation)

NOOP 是最简单的调度器,它几乎不做任何排序操作,仅执行基本的请求合并。请求按照到达顺序直接进入 FIFO 队列。

  • 工作机制: 仅进行前后请求的合并,不进行重排序。本质是一个简单的 FIFO 队列。
  • 优点: 调度开销极低,CPU 占用少。
  • 缺点: 对机械硬盘无任何寻道优化,性能极差。
  • 适用场景: 纯 SSD 或 NVMe 设备(无机械寻道时间),以及硬件 RAID 卡或智能控制器(硬件已做排序)。

2.2.4 Kyber

Kyber 是专为 快速设备(如 NVMe SSD) 设计的高性能调度器。它采用基于令牌桶的算法,动态控制提交到驱动层的 I/O 深度,以最小化延迟。

  • 工作机制: 维护读/写两个令牌桶。根据当前延迟反馈动态调整令牌发放速率。当延迟升高时,减少令牌发放以降低队列深度。
  • 优点: 延迟可控,对延迟尖峰有很好的抑制作用;调度开销低。
  • 缺点: 吞吐量可能不如 NOOP 或 mq-deadline;配置参数较少,调优空间有限。
  • 适用场景: 低延迟要求的 NVMe SSD、云原生存储节点。

2.2.5 BFQ (Budget Fair Queuing)

BFQ 是 CFQ 的现代替代品,专注于提供 更细粒度的公平性。它不仅分配时间片,还分配 I/O 带宽预算(以扇区数计量),并考虑进程的 I/O 模式。

  • 工作机制: 为每个进程维护一个预算(budget),预算用完后切换到下一个进程。支持低延迟模式,可对交互式进程进行优先响应。
  • 优点: 公平性极佳,交互式体验好;能有效防止 I/O 抖动。
  • 缺点: 调度开销较大,在高速 SSD 上可能成为瓶颈。
  • 适用场景: 桌面系统、多媒体编辑、需要稳定 I/O 延迟的嵌入式系统。
内核版本提示: 从 Linux 5.0 开始,CFQ 被移除,默认调度器切换为 mq-deadline(多队列版本的 Deadline)或 none(即 NOOP)。Kyber 和 BFQ 作为可选调度器保留。

2.3 调度器特性对比表

调度器 核心目标 调度开销 延迟表现 公平性 适用设备
CFQ 公平性 高 中等 优秀 HDD
Deadline 延迟保障 中 低(读) 一般 HDD / SSD
NOOP 低开销 极低 取决于硬件 无 SSD / NVMe / RAID
Kyber 延迟控制 低 低且稳定 中等 NVMe SSD
BFQ 细粒度公平 高 中等 极优 HDD / 低速SSD

2.4 调度器选择决策流程

在实际调优中,可参考以下决策树快速选择调度器:

I/O 调度器选择决策树 存储设备类型? HDD 机械硬盘 公平性优先? BFQ / CFQ Deadline SSD / NVMe 延迟敏感? Kyber NOOP / none 决策说明 • HDD 场景:优先考虑公平性(BFQ)或延迟保障(Deadline) • SSD/NVMe 场景:延迟敏感选 Kyber,吞吐优先选 NOOP • 硬件 RAID 卡:通常选 NOOP,由硬件处理排序

2.5 查看与切换调度器

在 Linux 系统中,可以通过 /sys/block/<device>/queue/scheduler 文件查看和修改当前调度器。

# 查看当前调度器(方括号内为当前生效的调度器)
cat /sys/block/sda/queue/scheduler
# 输出示例:[mq-deadline] kyber bfq none

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

# 永久修改(通过 udev 规则)
# /etc/udev/rules.d/60-iosched.rules
# ACTION=="add|change", KERNEL=="nvme*", ATTR{queue/scheduler}="kyber"
调优警告: 对于 NVMe 设备,不建议使用 BFQ 或 CFQ,其调度开销会显著降低吞吐量。对于 SATA SSD,Deadline 或 mq-deadline 通常是平衡延迟与吞吐的最佳选择。

2.6 多队列块层(blk-mq)与调度器

随着 NVMe 等高速设备的普及,传统单队列调度器(如 CFQ、Deadline)在锁竞争和扩展性上出现瓶颈。Linux 内核引入了 blk-mq(多队列块层) 架构。blk-mq 为每个 CPU 核心分配独立的软件队列,并映射到硬件队列,大幅降低了锁开销。

  • 传统调度器(单队列): CFQ、Deadline、NOOP。适用于单队列设备或兼容模式。
  • 多队列调度器(blk-mq): mq-deadline、Kyber、BFQ、none。专为 blk-mq 设计,支持多队列并行分发。

下表对比了传统调度器与多队列调度器的关键差异:

特性 传统调度器(单队列) 多队列调度器(blk-mq)
锁粒度 全局队列锁(高竞争) 每 CPU 软件队列锁(低竞争)
扩展性 差(CPU 核数 > 8 时瓶颈明显) 优秀(可线性扩展至数百核)
典型代表 CFQ, Deadline, NOOP mq-deadline, Kyber, BFQ, none
适用硬件 HDD, 低速 SSD NVMe, 高速 SSD, 多队列硬件
实践建议: 在 Linux 5.x 及更新版本的内核上,对于所有非 HDD 设备,优先使用 blk-mq 调度器。可以通过 lsblk -D 查看设备是否支持多队列。