linux io合并分front merge和back merge两类,前者要求新bio的end_sector等于队列首request的start_sector,后者更常见且开销更低,要求bio.start_sector等于队列尾request.end_sector。

Linux 的 IO 合并机制是内核在块层(block layer)对相邻或重叠的 IO 请求进行自动合并的关键优化手段,直接影响磁盘吞吐和延迟。调优 IO 合并不是简单开关某个参数,而是理解其触发条件、观察实际效果,并结合硬件特性与 workload 特征做针对性调整。
IO 合并在哪发生?两种类型要分清
Linux 中 IO 合并分为两类,发生在不同阶段:
- Front Merge(前向合并):新下发的 bio(块 IO 描述符)与请求队列中最前端已排队但尚未派发的 request 在逻辑块地址(LBA)上连续或重叠时,直接合并进该 request。依赖 request 的起始扇区和长度,要求新 bio 的 end_sector == 前一个 request 的 start_sector。
- Back Merge(后向合并):新 bio 与 request 队列中最后一个 request在 LBA 上连续或重叠(即 bio.start_sector == request.end_sector),则扩展原 request 的范围。这是更常见、开销更低的合并方式。
注意:合并只发生在同一 queue(如 /dev/sda 对应的 request_queue)内;跨设备、跨队列、带 barrier/fua 标志的 IO 通常不参与合并。
/sys/block/*/queue/ 相关参数的实际意义
以下路径下的文件可读写,但多数并非“开关”,而是影响合并行为的阈值或策略开关:
- iosched/xxx/slice_idle(仅 CFQ/DEADLINE):空闲时间窗口,影响调度器是否等待更多 IO 合并,非合并本身开关。
- max_sectors_kb:单个 request 最大允许扇区数(单位 KB)。设太小会强制拆分大 IO,抑制合并效果;设太大可能增加单次 IO 延迟。SSD 常设为 1024 或 2048,HDD 可保守设为 512。
- max_segments:单 request 最多允许的物理内存段数(SG list length)。DMA 映射受限时影响合并上限,NVMe 设备通常可设高(如 128),老 SATA 控制器建议保持默认(128 或 256)。
- nomerges:控制合并级别(0=全开,1=禁用 front/back merge,2=仅禁用 back merge)。生产环境一般不设为 1 或 2,除非调试确认合并引发异常(如某些旧阵列固件 bug)。
如何判断合并是否生效?别只看 iostat
iostat 的 rrqm/s 和 wrqm/s 是合并请求数(merged requests per second),但易被误解:
- 该值反映的是进入队列前被合并的次数,不是最终提交给设备的 IO 数量;即使显示为 0,也可能因队列深度低、IO 分散而未触发合并。
- 更准的方法是用
blktrace抓取块层事件:blktrace -d /dev/sda -o - | blkparse -i -,观察Q(queue)、M(merge)、G(get request)事件序列,确认 bio 是否真被合并进已有 request。 - 配合
/proc/diskstats中第 6/10 列(read/write merges)对比第 4/8 列(read/write completed),计算合并率:merges / (merges + completed),>10% 说明合并较活跃。
调优建议:按场景而非盲目改参
合并效果高度依赖 workload 模式和存储栈特性:
-
随机小 IO 密集型(如数据库 OLTP):合并收益有限,甚至因等待合并引入延迟。可适当降低
slice_idle(如 CFQ 下设为 0),或换用none(kyber)或mq-deadline调度器,减少合并等待。 -
顺序大 IO(如备份、视频转码):确保
max_sectors_kb足够(≥ 2048),关闭nomerges,让多个 4K bio 自动聚合成更大 request,提升吞吐。 -
混合读写 + 高并发:启用
rq_affinity=2(将 completion 绑定到下发 CPU),避免跨 CPU 合并失效;检查是否启用了多队列(multi-queue)——现代 NVMe/SATA-AHCI 默认开启,此时每个硬件队列独立合并,无需额外干预。
不复杂但容易忽略:合并是块层“被动优化”,无法替代应用层 IO 聚合(如 O_DIRECT + 大 buffer)或文件系统层预分配(fallocate)。真正有效的 IO 性能提升,往往来自三者协同。










