「银弹不存在」md RAID5/6 journal 实测:为什么它救不了 HDD 随机写

省流版:md journal 不是把 HDD 随机写变成 NVMe 随机写的魔法。它只负责 write-hole 保护和让回写更接近全条带写,持续的随机写能力仍由 HDD 自己决定。

1. 背景与假设:想用 NVMe 给 RAID6 续命

问题现场:底层是一组 12 LUN 的 RAID6,来自 6 块物理盘(双致动器,每块盘切出两个 LUN)。小随机写实测 10-17MB/s,业务入写基线约 18MB/s。入写大于落盘,脏数据持续累积,这是后续所有测试的起点。

现场有一块 256G NVMe,计划用它验证 md 的 journal 机制(raid5-cache):随机小写先顺序写入快速 journal 设备,md 应答后再批量落盘。按该机制,小随机写的前端速度应接近 journal 设备,即接近 NVMe 速度;18MB/s 的入写基线低于 NVMe 写入能力,RAID6 的 RMW 写惩罚预期被削弱。

2. 实验设计

实验环境为 Rocky 8.10 + kernel 7.1.4(elrepo),mdadm 支持 --add-journal。计划:给 md0 挂 256G NVMe 分区做 journal,用 fio 直接压 /dev/md0,对比加 journal 前后的随机写表现。

先跑峰值测试:

fio --filename=/dev/md0 --rw=randwrite --bs=4k --size=8G \
    --iodepth=64 --numjobs=4 --direct=1 --ioengine=libaio

--size=8G 用来测「纯 journal 峰值」——数据量小于 journal 容量时,最能体现 journal 的吸收速度。更极限的参数是:

fio --filename=/dev/md0 --rw=randwrite --bs=4k \
    --iodepth=128 --numjobs=8 --norandommap --direct=1 --randrepeat=0

配合 63.7T 全盘随机打范围,逼近真实压力。

监控同时开两条线:

iostat -x /dev/nvme1n1p1 1

看 journal 设备的吞吐;再采样 /sys/block/nvme1n1/nvme1n1p1/stat 的第 3、7 字段,分别对应「排水读 / 吸收写」两个方向。

3. 踩坑:journal 不是想加就能加

第一坑:journal 只支持 RAID5/6。RAID10 不支持,也不需要,镜像语义天然没有 RMW 和 write-hole 问题。本次实验在 RAID6 上操作,不涉及该限制;同一思路套到 RAID10 上无法执行。

第二坑:加 journal 要求阵列 readonly。直接执行:

mdadm --add-journal /dev/md0 /dev/nvme1n1p1

报错:

/dev/md0 is not readonly, cannot add journal

正确操作是先 umount、停掉上层的 bcache0,再执行:

mdadm --grow /dev/md0 --bitmap=none
mdadm --readonly /dev/md0
mdadm --add-journal /dev/md0 /dev/nvme1n1p1

bitmap 与 journal 互斥,必须先拆掉 bitmap。成功后 mdadm 会自动把阵列切回 read-write。等价做法是在建阵时用 --write-journal 指定 journal 设备,省去后续操作。

4. 9MB/s 与 write-through 假象

挂上 journal 后第一次峰值测试为 9MB/s,低于不挂 journal 的表现,也远低于 NVMe 速度。

该结果符合 write-through 模式的特征:journal 只记 intent,真正的写仍走 RAID6 RMW 路径,多一层簿记开销,因此更慢。查看:

cat /sys/block/md0/md/journal_mode

当前模式不是 write-back。手动切换:

echo write-back > /sys/block/md0/md/journal_mode

5. 更深的坑:缓冲不是产能

切到 write-back 后,短期峰值上升:journal 先吸收再排水,小随机写短暂贴近 journal 设备的吸收速度。

用户现场给出关键判断:write-back 下 journal 仍是「先吸收再排水」的缓冲。持续入写大于 HDD 落盘能力时,journal 会填满,填满后性能回到 HDD 原有水平。缓冲能削峰,不能增产。

监控数据与此一致:journal 采样时,吸收写为 2-24MB/s,排水读为 0。journal 未写满,压力不在 journal 容量侧,而在 HDD 侧的持续落盘能力。

6. 结论与边界

md journal 的价值是 write-hole 保护,以及让回写更接近全条带写、减少 RMW 惩罚。它不会把小随机写变成 NVMe 速度,小随机写的持续能力仍由 HDD 层决定。

真正削峰需要更大的缓存(如 1.2T bcache cache),前提是平均入写 < 平均落盘;否则再大的缓存也只是延后崩溃点。本项目最终放弃 journal,重建 RAID10。

复盘要点

  • 测 journal 先确认 journal_mode=write-back,否则测到的是 write-through 的 9MB/s 假象
  • 区分「峰值吸收」和「持续排水」两个指标:峰值看 journal 吸收速度,持续看 HDD 落盘速度
  • 任何缓冲类方案都先算「平均入写 vs 平均落盘」这笔账:入写长期大于落盘,缓冲必满,满了就打回原形
  • md journal 的价值是 write-hole 保护 + 让回写更接近全条带写,不是把小随机写变成 NVMe 速度
  • 加 journal 的姿势:仅 RAID5/6、阵列 readonly、bitmap 与 journal 互斥
标签:mdadm, RAID, journal