2. Linux IO栈全景:从VFS到块设备层、IO调度器与cgroup在栈中的位置、关键数据结构
理解Linux IO栈的全景是进行多租户IO性能调优的基础。本章将自上而下剖析IO栈的每一层,明确IO调度器与cgroup IO控制器在栈中的精确位置,并解析贯穿其中的关键数据结构。
2.1 Linux IO栈分层架构
Linux IO栈是一个高度模块化的分层体系,从应用程序的系统调用接口到物理磁盘的指令,共经历以下核心层次:
- VFS(虚拟文件系统)层:统一抽象所有文件系统,提供
read()/write()/open()等标准接口。 - 具体文件系统层:如ext4、XFS、Btrfs,负责将VFS请求转换为块级别的逻辑操作。
- 块层(Block Layer):核心调度与排队场所,包含IO调度器、cgroup IO控制器、请求合并与排序逻辑。
- 设备驱动层:与具体硬件(NVMe、SCSI、virtio-blk)交互,发送命令并处理中断。
- 物理设备层:磁盘、SSD或NVMe设备,执行实际的数据读写。
关键认知: 多租户场景下的IO隔离与优先级控制,主要发生在块层。IO调度器和cgroup IO控制器在此层协同工作,决定哪个IO请求先被处理。
2.2 IO调度器与cgroup在栈中的精确位置
在块层内部,IO调度器和cgroup IO控制器(blkio)的协作关系如下:
- cgroup IO控制器:位于块层入口处,负责根据cgroup配置(权重、上限、延迟)对IO请求进行分类和限流。
- IO调度器:位于cgroup控制器之后,负责对已分类的IO请求进行排序、合并和分发。常见的调度器包括:
mq-deadline、bfq、kyber、none。
数据流路径: 应用程序 → VFS → 文件系统 → cgroup blkio控制器 → IO调度器 → 驱动 → 设备。
2.3 关键数据结构
理解以下数据结构是深入调优的前提:
| 数据结构 | 所在层次 | 核心作用 | 关键字段 |
|---|---|---|---|
struct bio |
块层 | 描述一次底层IO请求(扇区、方向、数据页) | bi_sector, bi_size, bi_opf |
struct request |
块层/调度器 | 调度器管理的IO单元,可包含多个合并的bio | q, rq_flags, __sector |
struct request_queue |
块层 | 每个块设备对应一个请求队列,挂载调度器和cgroup策略 | elevator, mq_ops, blkcg |
struct blkcg_gq |
cgroup blkio | cgroup与请求队列的关联结构,存储权重与统计 | blkcg, q, weight |
struct elevator_queue |
IO调度器 | 调度器实例,包含调度算法特定的调度队列 | type, ops, hash |
常见误区: 初学者常混淆
struct bio 和 struct request。bio 是文件系统或VFS下发的原始IO单元,而 request 是经过块层合并、排序后的调度单元。一个 request 可以包含多个连续的 bio。
2.4 数据流全景:一次IO请求的完整旅程
以一次 read() 系统调用为例,数据流如下:
- VFS:根据文件描述符找到 inode,调用具体文件系统的
read_iter方法。 - 文件系统:将文件逻辑偏移转换为块号,构造
struct bio,调用submit_bio()。 - 块层入口:
submit_bio()进入通用块层,经过blk_cgroup_bio_start()进行cgroup记账。 - IO调度器:bio 被转换为
struct request,插入调度队列(如 deadline 的红黑树或 FIFO 队列)。 - 驱动提交:调度器通过
blk_mq_submit_bio()将 request 发送给设备驱动。 - 硬件完成:设备完成读写,触发中断,驱动回调完成函数,逐层向上通知。
2.5 多队列块层(blk-mq)简介
现代Linux内核(3.13+)默认使用多队列块层(blk-mq)以应对NVMe等高速设备。其核心变化在于:
- 单队列 → 多队列:每个CPU或硬件队列拥有独立的提交队列,减少锁竞争。
- IO调度器适配:传统调度器(如deadline)被改造为
mq-deadline,BFQ和Kyber也原生支持多队列。 - cgroup集成:cgroup blkio 在 blk-mq 中通过
blk_mq_ctx和blk_mq_hw_ctx实现精细控制。
性能提示: 对于NVMe SSD,推荐使用
none 调度器(即不调度)或 kyber,以降低延迟。对于HDD或混合负载,mq-deadline 或 bfq 能提供更好的公平性。
2.6 本章小结
Linux IO栈从VFS到块设备层,每一层都有明确的职责。IO调度器和cgroup blkio控制器位于块层核心,共同决定了多租户环境下的IO隔离与性能。关键数据结构 bio、request、request_queue 和 blkcg_gq 是理解IO路径的钥匙。掌握这些全景知识,才能在后继章节中精准调优。