存储-3-IO调度-2-相关文档(bfq-iosched.rst/blkio-controller.rst)
一、bfq-iosched.rst 翻译
==========================
BFQ(Budget Fair Queueing)
==========================
BFQ 是一个按比例共享(proportional-share)的 I/O 调度器,并带有额外的低时延能力。除了支持 cgroups(blkio 或 io 控制器)之外,BFQ 的主要特性包括:
- BFQ 能保证较高的系统与应用响应性,并为时延敏感应用(如音视频播放器)提供低时延;
- BFQ 按“带宽”而非仅按“时间片”在进程或组之间分配资源(在需要维持高吞吐时会回退到按时间分配)。
在默认配置下,BFQ 优先保证时延而非吞吐。因此,当为了降低时延有必要时,BFQ 可能构造出吞吐略低的调度序列。如果你在某个设备上的唯一目标是始终获得最大吞吐,应关闭全部低时延启发式:将 low_latency 设为 0。如何在时延与吞吐间取舍、或如何最大化吞吐,见第 3 节。
与其他 I/O 调度器一样,BFQ 会给每个 I/O 请求处理增加一定开销。为便于量化,这里给出一个示例:
BFQ 在单锁保护下的每请求总处理时间(即插入、派发、完成三个 hook 的执行时间之和)约为 1.9 us(Intel Core i7-2760QM@2.40GHz,使用简单代码插桩和 S 套件 [1] 的 throughput-sync.sh)。
作为对比,blk-mq 中更轻量的 mq-deadline 约为 0.7 us(mq-deadline 代码量约 800 行,BFQ 约 10500 行)。
调度开销会进一步限制 CPU 可处理的最大 IOPS(I/O 栈其他部分本身也会限制上限)。在启用完整层级支持(CONFIG_BFQ_GROUP_IOSCHED=y)且未开启 CONFIG_BFQ_CGROUP_DEBUG(见 4-2)时,BFQ 在下列 CPU 上的上限示例为:
- Intel i7-4850HQ:400 KIOPS
- AMD A8-3850:250 KIOPS
- ARM CortexTM-A53 八核:80 KIOPS
若开启 CONFIG_BFQ_CGROUP_DEBUG(且完整层级支持开启),由于会创建并更新全部 blkio.bfq* 统计项(见 4-2),可持续吞吐会下降。对应上面三台机器,最大可持续吞吐约为:
- Intel i7-4850HQ:310 KIOPS
- AMD A8-3850:200 KIOPS
- ARM CortexTM-A53 八核:56 KIOPS
BFQ 同样适用于多队列设备。
.. 下方为目录,可直接跳到第 3 节。
.. CONTENTS
1. 何时 BFQ 会有价值?
1-1 个人系统
1-2 服务器系统
2. BFQ 如何工作?
3. BFQ 的可调参数及正确配置方法
4. BFQ 组调度
4-1 提供的服务保证
4-2 接口
1. 何时 BFQ 会有价值?
BFQ 在个人系统和服务器系统上可带来以下收益。
1-1 个人系统
--------------------
交互式应用低时延
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
无论后台负载如何,BFQ 都能保证交互任务体验接近“设备空闲时”的响应性。比如即使后台正在执行:
- 读取、写入或复制一个或多个大文件;
- 编译源码树;
- 一个或多个虚拟机进行 I/O;
- 软件更新;
- 索引服务扫描文件系统并更新数据库;
此时启动应用、或在应用内加载文件,耗时都接近设备空闲时。对比 CFQ、NOOP、DEADLINE:在同等条件下应用会出现高时延,甚至在后台任务结束前卡顿(SSD 上同样可能出现)。
软实时应用低时延
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
音视频播放器/推流器等软实时应用,也能在后台 I/O 干扰下保持低时延与低丢包(丢帧)率,因此几乎不会因后台负载而出现明显卡顿。
代码开发类任务更快
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
若并行存在额外负载,BFQ 对典型开发任务(编译、checkout、merge 等)中的 I/O 相关阶段,
通常比 CFQ、NOOP、DEADLINE 更快。
高吞吐
^^^^^^^^^^^^^^^
在机械硬盘上,BFQ 在测试中的顺序负载吞吐可比 CFQ 高至 30%,比 DEADLINE/NOOP 高至 150%。在随机负载及闪存设备负载上,BFQ 吞吐通常与其他调度器相近。
强公平性、带宽与时延保证
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
BFQ 会按权重在 I/O 密集应用之间分配“设备吞吐”而非仅设备时间,且与负载模式、设备参数无关。基于这些带宽保证,可用简单公式推导出较紧的单请求时延保证。若未配置为严格服务保证模式,对于可能导致吞吐损失的应用,BFQ 会(仅)回退到基于时间的共享策略。
1-2 服务器系统
------------------
服务器收益大多来自上述同一服务属性。特别是,即使同时承载其他重负载,BFQ 仍可保证:
* 音视频流播放/推流的抖动和丢包率极低或接近 0;
* Web 页面及嵌入对象的快速获取;
* 在线数据采集/转储场景(例如抓包日志)的实时写入;
* 本地与远程访问服务器的响应性。
2. BFQ 如何工作
BFQ 是一个按比例共享 I/O 调度器,其总体结构及部分代码来源于 CFQ。
(1) 每个在设备上发起 I/O 的进程都会关联一个权重和一个 `(bfq_)queue`。
(2) BFQ 在一段时间内对某个队列(进程)授予设备独占访问,并通过为每个队列分配 “预算(budget)”来实现该模型,预算单位为扇区数。
(2.1) 队列获得设备访问后,每次派发请求,队列预算按请求大小递减。
(2.2) 在服役队列会在以下事件之一发生时过期(服务被挂起):1)预算耗尽,2)队列变空,3)“预算超时”触发。
- 预算超时用于防止随机 I/O 进程长时间占用设备并显著降低吞吐。
- 实际上,与 CFQ 类似,发同步请求的进程所对应队列在变空时不一定立即过期。BFQ 可能短暂 idle 设备,等待该进程及时发来新请求后继续服务。设备 idle 往往能提升旋转介质和非队列型闪存设备在同步顺序 I/O 场景下的吞吐。此外,在 BFQ 中,idle 也是保证同步请求进程获得目标吞吐份额的关键手段(详见本文 slice_idle 参数说明,或 [1, 2])。
- 从“服务保证”角度看,如果多个进程同时竞争设备且所有进程/组权重相同,BFQ 可在“完全不 idle 设备”的情况下仍保证预期吞吐分配,因此吞吐尽可能高。
- 对带内部命令队列的闪存设备(典型是 NCQ),idle 通常总会损害吞吐。因而 BFQ 仅在“服务保证必须”时执行 idle(例如为保证低时延或公平性)。此时总体吞吐可能次优。目前在这类设备上尚无同时满足“强服务保证”与“最优吞吐”的通用方案。
(2.3) 若开启低时延模式(默认开启),BFQ 会执行启发式检测交互应用与软实时应用 (如音视频播放器/推流器),并降低其时延。最关键动作是给这些应用对应队列分配超过公平份额的吞吐。为简洁起见,把这整套优待动作称为“提权(weight-raising)”。其中交互应用提权较温和,软实时应用提权更强。
(2.4) 对在“队列创建突发”中出现的队列,BFQ 会自动停用 idle。这些队列通常来自更偏吞吐的应用或服务进程,例如启动阶段的 systemd 或 git grep。
(2.5) 与 CFQ 一样,BFQ 会合并交错 I/O 队列(单看各自是随机 I/O,合并后趋于顺序)。但 BFQ 使用更快响应机制 EQM(Early Queue Merge)。EQM 能更早检测交错 I/O(协作进程),使 BFQ 即便在 CFQ 需要“抢占”机制才能保持高吞吐的场景中,也能通过队列合并保持高吞吐。因此 EQM 统一了交错 I/O 场景下的高吞吐手段。
(2.6) 队列按 WF2Q+ 的变体 B-WF2Q+ 调度,借助增强 rb-tree 实现 O(log N) 总体复杂度。详见 [2]。B-WF2Q+ 也天然支持层级调度,见第 4 节。
(2.7) B-WF2Q+ 相对理想、公平且平滑的服务模型,偏差很小。特别地,即使设备吞吐波动,且不受设备参数、当前负载、队列预算影响,B-WF2Q+ 仍保证每个队列按其权重比例获得设备吞吐份额。
(2.8) 最后一项“与预算大小无关”的性质(虽然乍看反直觉)实际上很有价值:
- 第一,任何按比例共享调度器相对理想服务的最大偏差都与最大预算(slice)成正比。因此 BFQ 的偏差能保持很小,不仅因为 B-WF2Q+ 本身精确,还因为 BFQ *不需要* 通过增大预算来让队列拿到更高吞吐份额。
- 第二,BFQ 可以为每个进程(队列)自由选择更匹配其需求或 I/O 模式的预算。BFQ 用简单的反馈回路算法动态更新预算,以在高吞吐与低时延保证之间取得平衡。当在服役队列过期时,该算法会计算其下一轮预算,以便:
1) 最终给顺序 I/O 的 I/O 密集型应用分配较大预算,因为单次连续服务越长,吞吐通常越高;
2) 最终给时延敏感应用(常见为间歇短 I/O)分配较小预算,因为等待服务队列预算越小,B-WF2Q+ 越快轮到它(见 [2] 的 3.3 小节)。
(3) 若多个进程同时竞争设备且进程/组权重一致,BFQ 可在不 idle 设备的情况下得到预期吞吐分配,此时会用抢占机制,且吞吐更高。
(4) ioprio class 间严格按优先级顺序服务:只要存在高优先级队列,低优先级队列不服务。同一 class 内按队列权重比例分配带宽。Idle class 仍会获得极薄的保底带宽,避免饿死。
3. BFQ 的可调参数及正确配置方法
BFQ 的大多数调参项会影响服务保证(主要是时延、公平性)与吞吐。要在两者之间取舍,重点看 slice_idle、strict_guarantees、low_latency;
要最大化吞吐,重点看 slice_idle、timeout_sync、max_budget。
其余性能相关参数多继承自 CFQ,主要为兼容保留。到目前为止,修改这些兼容参数在 BFQ 上很少带来明显性能提升。
特别是下文 back_seek-max、back_seek_penalty、fifo_expire_async、fifo_expire_sync 与 CFQ 基本一致,其说明沿用了 CFQ 描述。slice_idle 的部分说明也参考了 CFQ。
per-process ioprio and weight
-----------------------------
除非使用 cgroups 接口(见“4. BFQ 组调度”),否则进程权重只能通过 I/O 优先级间接设置,关系为:
weight = (IOPRIO_BE_NR - ioprio) * 10. //8, ioprio 越小 weight 越大。
注意:若 low_latency 打开,BFQ 会自动提高交互与软实时应用对应队列的权重。如果你需要精确控制权重,请关闭该项。
slice_idle
----------
该参数指定当某些同步 BFQ 队列变空时,BFQ 等待下一次 I/O 请求的 idle 时长。默认 slice_idle 非 0。idle 目的有二:提升吞吐、确保预期吞吐分配(见第 2 节)。
在寻道代价高的介质(如单盘 SATA/SAS 机械盘)上,idle 通常有利于减少寻道次数并提高吞吐。
将 slice_idle 设为 0 可移除队列 idle。在较快存储(如硬件 RAID 下多 SATA/SAS 盘,以及带内部命令队列/并行性的闪存设备)上,通常可提升整体吞吐。
因此,是否设为 0 取决于设备和负载。一般而言:
- SATA/SAS 单盘及其软件 RAID,保持 slice_idle 打开通常更有利;
- 单 LUN 背后有多主轴(主机侧硬 RAID 或阵列)或快速闪存存储,slice_idle=0 可能带来更高吞吐且时延仍可接受。
但在“权重差异”或“请求长度差异”场景下,idle 是实现服务保证所必需。举例:若队列 A 相比队列 B 需要连续派发多个请求,idle 能确保 A 在刚变空后很快补发新请求时,不会被 B 的请求插入打断,从而保持 A 在 B 下次派发前继续拿到多个派发机会。
请注意,这里保证的是“派发顺序层面”的差异化;若要保证实际服务顺序也严格对应派发顺序,还需设置 strict_guarantees。
idle 也有明显副作用:在不利于吞吐的场景下(典型是随机负载)会显著降低吞吐。因此 BFQ 在“对吞吐无益”时会尽量避免 idle(见第 2 节)。由此,加上 strict_guarantees 相关的附加因素,短期服务保证可能偶尔被打破。但某些场景中这些短期保证比最大吞吐更重要,例如视频播放/推流中低丢帧率往往比峰值吞吐更重要。此时可考虑设置 strict_guarantees。
slice_idle_us
-------------
与 slice_idle 控制同一参数,但单位是微秒。二者任意一个都可设置 idle 行为;设置后,另一个 sysfs 参数会反映新值。
strict_guarantees
-----------------
若设置该参数(默认未设置),则 BFQ 会:
- 在服役队列变空时始终执行 idle;
- 强制设备一次只服务一个 I/O 请求:只有不存在未完成请求时才派发新请求。
在存在权重差异或请求大小差异时,上述两条都需要,才能保证每个 BFQ 队列拿到应得带宽份额。第一条原因见 slice_idle 说明;第二条是因为现代存储设备会在内部重排排队请求,这可能直接破坏调度器在派发层面建立的服务保证。
设置 strict_guarantees 会影响吞吐,这是预期行为。
back_seek_max
-------------
单位 Kbytes,指定“向后寻道”的最大距离。该距离是从当前磁头位置到后向扇区的空间跨度。
该参数允许调度器提前考虑“后向”请求:若其距离在阈值内,可将其视为“下一个”请求。
back_seek_penalty
-----------------
用于计算向后寻道代价。若后向请求距离仅为前向请求的 1/back_seek_penalty,则二者寻道代价视为等价。
此时调度器不会偏向某一请求(否则会偏向前向请求)。默认值为 2。
fifo_expire_async
-----------------
异步请求超时时间。默认 248ms。
fifo_expire_sync
----------------
同步请求超时时间。默认 124ms。若希望相对偏向同步请求,应把该值设置得低于 fifo_expire_async。
low_latency
-----------
启用/禁用 BFQ 低时延模式。默认启用。启用后,交互与软实时应用会被优待并获得更低时延,机制见第 2 节。
如果你需要完全控制带宽分配,请关闭该模式。因为开启后 BFQ 会自动提升被优待应用的带宽份额。
此外,正如文档开头所述:如果你唯一目标是高吞吐,也应关闭该模式。因为优待部分应用的 I/O 可能降低总吞吐。对非旋转设备,要拿到尽可能高吞吐,可能还需将 slice_idle 设为 0(代价是放弃强公平/低时延保证)。
timeout_sync
------------
队列一旦被选中进入服务后,可连续占用设备的最长时间。在寻道代价高的设备上,增大该值通常有助于提高峰值吞吐。但同时会降低短期带宽与时延保证的粒度,尤其是下一个参数为 0 时更明显。
max_budget
----------
单个 BFQ 队列进入服务后可获得的最大服务量,单位扇区(当然仍受 timeout_sync 限制)。根据算法特性,该值越大,在顺序 I/O 占比越高时吞吐越高;代价是短期带宽/时延保证粒度变粗。
默认值为 0,表示自动调优:BFQ 会根据估计峰值速率,把 max_budget 设置为 timeout_sync 时间内可服务的最大扇区数。
针对特定设备,有用户反馈显式设置 max_budget(设置为 >0,且高于自动调优值)可获得更高吞吐。另一种达到相近效果的方法是:保持 max_budget=0,只提高 timeout_sync。
weights
-------
只读参数,用于展示当前活跃 BFQ 队列的权重。注: 5.4内核上已没有这个文件了。
4. BFQ 组调度
BFQ 同时支持 cgroups-v1 与 cgroups-v2 的 io 控制器,即 blkio 与 io。BFQ 支持基于权重的按比例共享。要激活 cgroups 支持,设置 CONFIG_BFQ_GROUP_IOSCHED。
4-1 提供的服务保证
-------------------------------
在 BFQ 下,按比例共享表示“设备带宽”的真实按比例分配,而不是仅时间按比例。例如权重 200 的组可获得约两倍于权重 100 组的带宽。
BFQ 支持任意深度层级(组树)。带宽分配符合直觉:对每个组,其子节点按权重比例共享该组总带宽。特别地,这意味着:对于每个叶子组,除非修改进程 ioprio,该组内各进程获得的“整个组带宽份额”相同。
若严格按带宽保证会导致吞吐损失过大,组的资源共享保证可能部分或全部从“带宽”切换为“时间”。该切换按“每进程”进行:若叶子组中某进程以其带宽份额服务会引起明显吞吐下降,BFQ 会仅对该进程回退到按时间比例共享。
4-2 接口
-------------
若要在某设备上使用 BFQ 的按比例带宽共享,前提当然是该设备的活动调度器就是 BFQ。
在每个组目录下,BFQ 专属 cgroup 参数与统计文件都以 "bfq." 为前缀。因此在 cgroups-v1 或 cgroups-v2 中,完整前缀分别是 "blkio.bfq." 与 "io.bfq."。例如,设置组权重的参数文件是 blkio.bfq.weight 或 io.bfq.weight。
对于 cgroups-v1(blkio 控制器),bfq 创建并持续更新哪些统计文件,取决于 CONFIG_BFQ_CGROUP_DEBUG 是否开启:
- 若开启,则会创建 Documentation/admin-guide/cgroup-v1/blkio-controller.rst 中文档化的全部统计文件;
- 若未开启,则仅创建:
blkio.bfq.io_service_bytes
blkio.bfq.io_service_bytes_recursive
blkio.bfq.io_serviced
blkio.bfq.io_serviced_recursive
CONFIG_BFQ_CGROUP_DEBUG 的取值(y/n)对 BFQ 的可持续最大吞吐影响很大,因为更新 blkio.bfq.* 统计项本身代价较高(其中部分统计在开启 DEBUG 时才启用)。
/dev/blkio/background # ls -l -r--r--r-- 1 root root 0 2026-06-26 17:49 blkio.bfq.io_service_bytes -r--r--r-- 1 root root 0 2026-06-26 17:49 blkio.bfq.io_service_bytes_recursive -r--r--r-- 1 root root 0 2026-06-26 17:49 blkio.bfq.io_serviced -r--r--r-- 1 root root 0 2026-06-26 17:49 blkio.bfq.io_serviced_recursive -rw-r--r-- 1 root root 0 1970-01-01 08:00 blkio.bfq.weight -rw-r--r-- 1 root root 0 2026-06-26 17:49 blkio.bfq.weight_device --w------- 1 root root 0 2026-06-26 17:49 blkio.reset_stats -rw-r--r-- 1 root root 0 2026-06-26 17:49 cgroup.clone_children -rw-rw-r-- 1 system system 0 1970-01-01 08:00 cgroup.procs -rw-r--r-- 1 root root 0 2026-06-26 17:49 notify_on_release -rw-rw-r-- 1 system system 0 2026-06-25 15:58 tasks
可设置参数
-----------------
每个组可设置的参数只有下列一项:
weight(即 blkio.bfq.weight 或 io.bfq.weight):组在父组内的权重。取值范围 1..10000(默认 100)。
本节开头给出的 ioprio 与 weight 的线性映射仍然有效,但超过 IOPRIO_BE_NR*10 的权重,会映射为 ioprio 0。
再次提醒:若 low_latency 已设置,BFQ 会自动提升交互与软实时应用队列的权重。如果你希望自行控制权重,应关闭该选项。
[1]
P. Valente, A. Avanzini, "Evolution of the BFQ Storage I/O Scheduler", Proceedings of the First Workshop on Mobile System Technologies (MST-2015), May 2015.
http://algogroup.unimore.it/people/paolo/disk_sched/mst-2015.pdf
[2]
P. Valente and M. Andreolini, "Improving Application Responsiveness with the BFQ Disk I/O Scheduler", Proceedings of the 5th Annual International Systems and Storage Conference
(SYSTOR '12), June 2012.
Slightly extended version: http://algogroup.unimore.it/people/paolo/disk_sched/bfq-v1-suite-results.pdf
[3]
https://github.com/Algodev-github/S
补充
1. 对交互型和软实时应用的识别
交互型主要看“长时间 idle 后重新活跃”,软实时主要看“周期性、低带宽、受速率上限约束”的 I/O 模式。
不是靠 Android framework 给 BFQ 打标签,也不是识别“前台 Activity / 音视频 App 名字”。
BFQ 识别的是队列的 I/O 行为模式,不是应用语义。 也就是说,它在块层看一个 bfq_queue 的请求到达节奏、空闲时间、吞吐速率、是否 seeky、是否处于大 burst 中,然后把这个队列“推断”为 interactive 或 soft real-time。
同一个 App 可能对应多个 I/O 队列,BFQ 并不知道“这个包名是音乐播放器”,它只根据 I/O 模式推断“这个队列像不像交互型/软实时型”。
1.1 interactive 的识别:
条件很直接:不在 large burst 里, 这个队列之前 idle 了足够长时间, 重新活跃后,会被认为值得 weight-raising, 真正的 interactive 判定代码是:
idle_for_long_time = bfq_bfqq_idle_for_long_time(...)
*interactive = !in_burst && idle_for_long_time
见 bfq-iosched.c 和 bfq-iosched.c。
而 “idle 够久” 的定义在 bfq-iosched.c, 当前没有正在派发中的请求:bfqq->dispatched == 0, 当前时间已经晚于:budget_timeout + bfq_wr_min_idle_time。也就是说,一个队列如果空闲了一段最小时间,之后又重新发起 I/O,BFQ 会把它看作可能是交互型队列。
默认这个最小 idle 时间是 2 秒,定义在 bfq-iosched.c:bfqd->bfq_wr_min_idle_time = msecs_to_jiffies(2000);
所以可以粗暴理解为:长时间没动,突然来一小波同步 I/O,不像后台批处理的大 burst,BFQ 就倾向于认为这是交互型。这和桌面/手机上“用户点一下应用,触发一次短促 I/O”这种模式是吻合的。
1.2 soft real-time 的识别
soft real-time 不是靠包名,而是靠I/O 节奏像流媒体/音视频那样稳定、低带宽、成批次、批次之间有处理间隔。
直接判定条件在 bfq-iosched.c:
bfq_wr_max_softrt_rate > 0
!BFQQ_TOTALLY_SEEKY(bfqq)
!in_burst
time_is_before_jiffies(bfqq->soft_rt_next_start)
bfqq->dispatched == 0
拆开说:不能是 totally seeky 的随机乱跳队列, 不能处于大 burst, 必须满足一个“下一次请求到来时间”的下界约束, 当前不能还有未完成派发请求, 最关键的是 soft_rt_next_start,它的设计目的在代码注释里解释得非常详细,见 bfq-iosched.c。
代码说明了 soft real-time 需要满足两类特征:
(1) 平均带宽不能太高;
(2) 请求模式要接近 isochronous。意思是:发一批请求, 等这批请求完成, 停一会儿做数据处理, 再发下一批.这很像音视频播放、录制、推流。
soft_rt_next_start 的计算公式在 bfq-iosched.c:取三者最大值(旧的 soft_rt_next_start, 基于“这批已服务数据量 / 允许的软实时最大速率”算出来的下次最早启动时间, 当前时刻 + slice_idle + 额外 4 jiffies)
所以 BFQ 的意思是:如果你下一批请求来得太快,说明你更像 greedy / I/O-bound 队列,不像软实时。如果你有处理间隔,而且平均带宽不高,才更像 soft real-time。
soft real-time 的带宽阈值在 bfq-iosched.c:bfqd->bfq_wr_max_softrt_rate = 7000,后面的注释写得很直白:这是“播放或录制压缩高清录像所需的大致速率”。也就是说,BFQ 默认把“类似压缩高清视频播放/录制的速率级别”当作 soft real-time 的参考上限。
1.3 优待逻辑
一旦判定为 interactive 或 soft real-time,就进入 weight-raising 路径。相关逻辑在 bfq-iosched.c 和 bfq-iosched.c。默认 interactive 的权重提升系数来自 bfq-iosched.c:bfqd->bfq_wr_coeff = 30
也就是被认定为该类队列后,BFQ 会把它的调度权重明显放大,从而让它更快拿到设备服务。
1.4 小结
识别 interactive: 像不像“长时间安静,偶尔被用户触发,然后来一阵短促同步 I/O”的队列;
识别 soft real-time: 像不像“低带宽、周期性、一批一批发、批次之间有处理停顿”的队列;
2. 小结
bfq 支持 blkio cgroup带宽控制,支持基于 ioprio 的IO优先级。
二、blkio-controller.rst
===================
块 I/O 控制器
===================
概述
========
cgroup 子系统 "blkio" 实现了块 I/O 控制器。存储层级中,叶子节点与中间节点都存在多种 I/O 控制策略需求(例如按比例分配带宽、最大带宽限制)。
设计目标是:blkio 控制器统一采用同一套基于 cgroup 的管理接口,并根据用户选项在后台切换具体 I/O 策略。
其中一种 I/O 控制策略是限速(throttling)策略,可用于指定设备 I/O 速率上限。该策略实现于通用块层,不仅可用于叶子节点,也可用于如 device mapper 这类上层逻辑设备。
1. 如何使用
限速/上限策略
-----------------------------
- 启用块 I/O 控制器::
CONFIG_BLK_CGROUP=y
- 在块层启用限速::
CONFIG_BLK_DEV_THROTTLING=y
- 挂载 blkio 控制器(见 cgroups.txt 中 “Why are cgroups needed?”)::
mount -t cgroup -o blkio none /sys/fs/cgroup/blkio
- 为 root 组在某个设备上设置带宽限制。策略格式为 "<major>:<minor> <bytes_per_second>"::
echo "8:16 1048576" > /sys/fs/cgroup/blkio/blkio.throttle.read_bps_device
上述命令会把主次设备号为 8:16 的设备在 root 组上的读速率限制为 1MB/s。
- 运行 dd 读取文件,观察速率是否被限制到 1MB/s::
# dd iflag=direct if=/mnt/common/zerofile of=/dev/null bs=4K count=1024 1024+0 records in 1024+0 records out 4194304 bytes (4.2 MB) copied, 4.0001 s, 1.0 MB/s
写入上限可通过 blkio.throttle.write_bps_device 设置。
2. 层级 cgroups
throttling 实现了层级支持;不过,只有在 cgroup 侧启用 "sane_behavior" 时,该层级支持才会生效。而 "sane_behavior" 目前是开发选项,尚未正式对外提供。
如果有人创建如下层级::
root / \ test1 test2 | test3
在开启 "sane_behavior" 时,throttling 会正确处理该层级。对 throttling 而言:所有 limit 作用于整棵子树;而统计仅针对该 cgroup 内任务直接产生的 I/O(本地统计)。
若 cgroup 侧未开启 "sane_behavior",throttling 实际上会把所有组当成同一层,效果近似如下::
pivot / / \ \ root test1 test2 test3
3. 用户可见的配置项
CONFIG_BLK_CGROUP - 块 I/O 控制器。
CONFIG_BFQ_CGROUP_DEBUG - 调试辅助。当前若开启该选项,cgroup 下会出现一些额外统计文件。
CONFIG_BLK_DEV_THROTTLING - 在块层启用块设备限速支持。
4. cgroup 文件详解
/dev/blkio/background # ls -l -r--r--r-- 1 root root 0 2026-06-26 17:49 blkio.bfq.io_service_bytes -r--r--r-- 1 root root 0 2026-06-26 17:49 blkio.bfq.io_service_bytes_recursive -r--r--r-- 1 root root 0 2026-06-26 17:49 blkio.bfq.io_serviced -r--r--r-- 1 root root 0 2026-06-26 17:49 blkio.bfq.io_serviced_recursive -rw-r--r-- 1 root root 0 1970-01-01 08:00 blkio.bfq.weight -rw-r--r-- 1 root root 0 2026-06-26 18:25 blkio.bfq.weight_device --w------- 1 root root 0 2026-06-26 17:49 blkio.reset_stats -rw-r--r-- 1 root root 0 2026-06-26 17:49 cgroup.clone_children -rw-rw-r-- 1 system system 0 1970-01-01 08:00 cgroup.procs -rw-r--r-- 1 root root 0 2026-06-26 17:49 notify_on_release -rw-rw-r-- 1 system system 0 2026-06-25 15:58 tasks
按比例权重策略文件
--------------------------------
- blkio.weight
指定每个 cgroup 的权重。这是该组在所有设备上的默认权重,除非被按设备规则覆盖(见 blkio.weight_device)。当前允许范围为 10 到 1000。
- blkio.weight_device
可通过该接口为“每 cgroup、每设备”设置规则。这些规则会覆盖 blkio.weight 指定的组默认权重。
格式如下::
# echo dev_maj:dev_minor weight > blkio.weight_device
在此 cgroup 中给 /dev/sdb (8:16) 配置 weight=300::
# echo 8:16 300 > blkio.weight_device # cat blkio.weight_device dev weight 8:16 300
在此 cgroup 中给 /dev/sda (8:0) 配置 weight=500::
# echo 8:0 500 > blkio.weight_device # cat blkio.weight_device dev weight 8:0 500 8:16 300
删除此 cgroup 中 /dev/sda 的专属权重::
# echo 8:0 0 > blkio.weight_device # cat blkio.weight_device dev weight 8:16 300
注:主次设备号对应的设备使用 bfq 调度类才能echo成功。cat /proc/partitions 看主次设备号,echo bfq > /sys/block/X/queue/scheduler 配置为 bfq 调度类。
- blkio.time
该 cgroup 在各设备上分配到的磁盘时间(毫秒)。前两列为设备主次号,第三列为分配给该组的磁盘时间(毫秒)。
- blkio.sectors
该组向磁盘读写的扇区数。前两列为设备主次号,第三列为该组在该设备上的传输扇区数。
- blkio.io_service_bytes
该组与磁盘之间传输的字节数。进一步按操作类型细分:read/write、sync/async。前两列为设备主次号,第三列为操作类型,第四列为字节数。
- blkio.io_serviced
该组向磁盘发出的 I/O(bio)数量。进一步按操作类型细分:read/write、sync/async。前两列为设备主次号,第三列为操作类型,第四列为 I/O 数量。
- blkio.io_service_time
该 cgroup 的 I/O 从请求派发到请求完成的总时间。单位纳秒(便于在闪存设备上也有意义)。当 queue depth=1 时,该时间可视为实际服务时间;当 queue_depth > 1 时则不再成立,因为请求可能乱序完成。这会导致某个 I/O 的服务时间中包含其他 I/O 的服务时间,从而出现 total io_service_time > 实际流逝时间。
同样按 read/write、sync/async 细分。前两列为设备主次号,第三列为操作类型,第四列为 io_service_time(ns)。
- blkio.io_wait_time
该 cgroup 的 I/O 在调度器队列中等待服务的总时间。由于是所有 I/O 的累计等待时间,该值可大于总流逝时间。它不是“该 cgroup 总等待时长”,而是各 I/O 等待时长之和。对 queue_depth > 1 的设备,该指标不包含 I/O 被派发到设备后、到实际被服务前的等待时间(设备重排请求会带来这段时延)。单位纳秒(便于闪存设备统计)。
按 read/write、sync/async 细分。前两列为设备主次号,第三列为操作类型,第四列为 io_wait_time(ns)。
- blkio.io_merged
合并进本 cgroup 请求中的 bio/request 总数。按 read/write、sync/async 细分。
- blkio.io_queued
在任意时刻该 cgroup 排队中的请求总数。按 read/write、sync/async 细分。
- blkio.avg_queue_size
仅在 CONFIG_BFQ_CGROUP_DEBUG=y 时提供,属调试辅助。表示该 cgroup 从创建以来的平均队列长度。每当该 cgroup 某个队列获得一次 timeslice 时采样。
- blkio.group_wait_time
仅在 CONFIG_BFQ_CGROUP_DEBUG=y 时提供,属调试辅助。表示 cgroup 自变忙(即排队请求数从 0 到 1)后,到其某个队列获得 timeslice 之间所等待的时间。这与 io_wait_time 不同:io_wait_time 是该组内每个 I/O 在调度队列中的等待时长累计值。单位纳秒。
若在 cgroup 正处于等待 timeslice 状态时读取,统计只包含到上次获得 timeslice 为止的累计值,不含当前这段增量。
- blkio.empty_time
仅在 CONFIG_BFQ_CGROUP_DEBUG=y 时提供,属调试辅助。表示 cgroup 在“未被服务且没有挂起请求”状态下持续的时间。不包含 cgroup 某个队列被 idle 等待的时间。单位纳秒。若在 cgroup 处于 empty 状态时读取,统计只包含到上次存在挂起请求为止的累计值,不含当前这段增量。
- blkio.idle_time
仅在 CONFIG_BFQ_CGROUP_DEBUG=y 时提供,属调试辅助。表示 I/O 调度器为该 cgroup idle 等待、以期等到比其他队列 /cgroup 现有请求更优请求的时间。单位纳秒。若在 cgroup 处于 idling 状态时读取,统计只包含到上次 idle 周期为止的累计值,不含当前这段增量。
- blkio.dequeue
仅在 CONFIG_BFQ_CGROUP_DEBUG=y 时提供,属调试辅助。给出该组从设备服务树中被 dequeue 的次数。前两列为设备主次号,第三列为该组在该设备上的 dequeue 次数。
- blkio.*_recursive
各类统计的递归版本。这些文件展示的信息与非递归文件相同,但会包含所有子孙 cgroup 的统计。
限速/上限策略文件
-----------------------------------
- blkio.throttle.read_bps_device
指定设备读速率上限,单位 bytes/s。规则按设备生效。格式如下::
echo "<major>:<minor> <rate_bytes_per_second>" > /cgrp/blkio.throttle.read_bps_device
- blkio.throttle.write_bps_device
指定设备写速率上限,单位 bytes/s。规则按设备生效。格式如下::
echo "<major>:<minor> <rate_bytes_per_second>" > /cgrp/blkio.throttle.write_bps_device
- blkio.throttle.read_iops_device
指定设备读 IOPS 上限,单位 IO/s。规则按设备生效。格式如下::
echo "<major>:<minor> <rate_io_per_second>" > /cgrp/blkio.throttle.read_iops_device
- blkio.throttle.write_iops_device
指定设备写 IOPS 上限,单位 IO/s。规则按设备生效。格式如下::
echo "<major>:<minor> <rate_io_per_second>" > /cgrp/blkio.throttle.write_iops_device
注意:若同一设备同时配置了带宽(BW)和 IOPS 规则,则 I/O 会同时受两种约束。
- blkio.throttle.io_serviced
该组向磁盘发出的 I/O(bio)数量。进一步按操作类型细分:read/write、sync/async。前两列为设备主次号,第三列为操作类型,第四列为 I/O 数量。
- blkio.throttle.io_service_bytes
该组与磁盘之间传输的字节数。进一步按操作类型细分:read/write、sync/async。前两列为设备主次号,第三列为操作类型,第四列为字节数。
各策略共用文件
-----------------------------------
- blkio.reset_stats
向该文件写入一个整数会重置该 cgroup 的全部统计数据。
三、Kconfig.iosched
注: 翻译自 block/Kconfig.iosched
if BLOCK menu "IO Schedulers" config MQ_IOSCHED_DEADLINE tristate "MQ deadline I/O scheduler" default y ---help--- deadline IO 调度器的 MQ(多队列)版本。 config MQ_IOSCHED_KYBER tristate "Kyber I/O scheduler" default y ---help--- Kyber I/O 调度器是一个低开销调度器,适用于多队列以及其他高速设备。给定读请求和同步写请求的目标时延后,它会自动调优队列深度以实现该目标。 config IOSCHED_BFQ tristate "BFQ I/O scheduler" ---help--- 面向 BLK-MQ 的 BFQ I/O 调度器。BFQ 会按照各进程权重在所有进程之间分配设备带宽,且不受设备参数和负载类型影响。它还可为交互式和软实时应用提供低时延保障。 详情见 Documentation/block/bfq-iosched.rst config BFQ_GROUP_IOSCHED bool "BFQ hierarchical scheduling support" depends on IOSCHED_BFQ && BLK_CGROUP ---help--- 启用 BFQ 的层级调度能力,使用 blkio(cgroups-v1)或 io(cgroups-v2)控制器。 config BFQ_CGROUP_DEBUG bool "BFQ IO controller debugging" depends on BFQ_GROUP_IOSCHED ---help--- 启用一些调试辅助功能。目前会在 cgroup 中导出额外的统计文件,便于调试。 endmenu endif
posted on 2026-06-26 18:00 Hello-World3 阅读(9) 评论(0) 收藏 举报
浙公网安备 33010602011771号