真正体现内核IO合并效果的字段是avgrq-sz和r_ios与r/s的比值:avgrq-sz显著大于8(即>4KB)且r/s远高于r_ios,表明block layer有效合并了小请求;反之则合并失效。

iostat -x 输出里哪个字段反映读写合并效率
真正体现内核 IO 合并效果的字段是 avgrq-sz(平均请求大小,单位扇区)和 avgqu-sz(平均队列长度),但它们本身不直接叫“合并效率”,而是通过比值间接暴露合并程度。
关键逻辑:如果上层发来大量小请求(比如 4K),而 avgrq-sz 显著大于 8(即 >4KB),说明内核在 block layer 做了有效合并;若长期接近 8,基本没合并,请求原样下发。
-
avgrq-sz÷ 2 = 平均请求字节数(因 1 扇区 = 512B);例如值为 64 → 实际平均请求大小为 32KB - 对比
r/s和r_ios:若r/s远高于r_ios,说明大量请求被合并成更少的底层 I/O —— 这就是合并生效的证据 -
avgqu-sz低 +avgrq-sz高 → 合并充分、设备负载轻;反之avgqu-sz高 +avgrq-sz低 → 请求碎片化严重,可能触发高延迟
为什么不能只看 r/s 和 w/s 判断合并效果
r/s 和 w/s 是提交到队列前的逻辑请求数,已被内核 IO 调度器(如 mq-deadline)合并或排序,它不反映真实设备压力,尤其在启用多队列(NVMe)、virtio 或 dm-thin 的场景下失真严重。
典型误判场景:
- 一个应用发出 1000 次 4K 写,
w/s显示 1000,但w_ios只有 120 → 实际设备只收到 120 个请求,合并率约 88% - 使用
dd bs=4k测试时,w/s≈w_ios→ 几乎无合并,因为direct=1绕过 page cache,且顺序流难以触发邻近块合并 - 数据库随机写负载下,
r/s看似不高,但r_ios持续 >5K,avgrq-sz却只有 8.2 → 合并几乎失效,IOPS 压力真实存在
如何用 pidstat 或 iotop 辅助验证合并是否发生在用户侧
合并行为分两层:上层(如文件系统、page cache)可能提前合并连续写;下层(block layer)负责物理扇区对齐与邻近请求聚合。要区分责任归属,得看进程级 IO 特征。
- 运行
pidstat -d 1,观察某进程的rkB/s和rrq/s(读请求速率):若rrq/s很低但rkB/s很高 → 进程自身发大块 IO,合并压力小 - 用
iotop -oP查看 “DISK READ/WRITE” 列:该值含缓存,不代表真实下发;但若某进程显示 “DISK READ: 50M/s” 而iostat -x中rMB/s仅 5M/s → 说明 90% 数据来自 page cache,根本没走到设备层,谈不上合并 - 真正需要关注的是
pidstat -d的areq-sz(平均请求大小,单位 KB):它反映该进程实际发出的 IO 大小,若长期 ≤4,说明应用层就没发大 IO,合并只能靠 kernel 强行凑,效果有限
fio 测试中如何人为控制合并程度
fio 不会自动合并请求,它按你指定的 bs 和 iodepth 直接压测。但你可以用参数模拟不同合并条件:
- 加
--mergeable=1(仅 libaio 引擎支持):允许 kernel 尝试合并相邻异步请求 - 用
--rw=randwrite --bs=4k --iodepth=1→ 强制最小粒度、单队列深度,抑制合并,测纯 IOPS 下限 - 改用
--rw=write --bs=128k --numjobs=1→ 大块顺序写,天然利于合并,avgrq-sz会飙升,w_ios显著低于w/s - 注意:
--direct=1必须开启,否则avgrq-sz反映的是 VFS 层逻辑块,不是 block layer 真实请求
合并效率不是固定值,它随 workload、IO 调度器策略、设备类型动态变化;avgrq-sz 和 r_ios/r/s 的差值才是最实在的观测锚点,别只盯着单个数字。


















