linux

如何将4个磁盘的mdadm RAID10迁移到RAID5上

我在Debian Buster下有一个基于Linux的mdadm的软件RAID10。最初我发现RAID10的性能最好。但我需要更多的空间,并接受用一些写入性能来换取+50%的空间。

# 猫 /proc/mdstat
Personalities : [raid10] [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4]
md1 : active raid10 sdd1[5] sda1[4] sdb1[1] sdc1[2]
      3899738112 blocks super 1.2 512K chunks 2 near-copies [4/4] [UUUU]
      bitmap: 3/30 pages [12KB], 65536KB chunk

unused devices: <none>

这个存储是通过NFS提供的,理想情况下,RAID可以在不停机的情况下进行转换。是的,我有备份,故障不会很严重,但如果它能工作,为什么不在不中断的情况下进行迁移呢。

我发现一篇 2012 年的文章描述了这个过程。事实证明,这些命令是完全正确的。当时作者遇到的问题是 mdadm 实用程序(或者可能是内核驱动程序)使用第一个命令立即挂起系统。从那时起,这个问题似乎已经得到解决。

https://www.tummy.com/blogs/2012/03/29/changing-a-raid-10-into-a-raid-5/

在mdadm中没有从RAID10→RAID5的直接路径。相反,你必须先将其降级为RAID0。

# mdadm --grow /dev/md1 --level=0 --raid-devices=2
mdadm: /dev/md1: could not set level to raid0

这立即生效,使 2 台设备发生故障并从阵列中移除。不幸的是,RAID 级别没有设置为 RAID0。 dmesg 显示:

md/raid0:md1: All mirrors must be already degraded!
md: md1: raid0 would not accept array

我发现问题是 sysfs 报告阵列没有降级,尽管它实际上是并且 mdadmcat /proc/mdstat 正确显示:

# cat /sys/block/md1/md/degraded
0

我发现没有其他方法可以解决这个问题,只能停止NFS服务器,卸载文件系统,关闭LUKS设备,停止RAID阵列,重新组装RAID阵列并重新启动所有服务。之后,它被正确地报告为降级,并且可以被转化为RAID0。

然后我可以用RAID5把它增加到4个设备。

# mdadm --grow /dev/md1 --level=5 --raid-devices=5 --add /dev/sdb1 /dev/sdd1

与以往不同的是 cat /proc/mdstat 没有显示正在进行的“重建”,而是显示“重塑”。这花费了相当长的时间(大约 10 小时),并且系统的响应速度比 RAID10 重建期间慢得多。我把它单独留在了重建时间。

由于重塑已经完成,RAID5很干净,速度也很好。我在测量时可能犯了错误,但现在的读取速度比我之前记录的要快,而写入速度对我来说也是可以接受的。

# 猫 /proc/mdstat
Personalities : [raid10] [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4] 
md1 : active raid5 sdd1[5] sdb1[3] sda1[4] sdc1[7]
      5849607168 blocks super 1.2 level 5, 512k chunk, algorithm 2 [4/4] [UUUU]

unused devices: <none>

(免责声明:整个故事是在迁移完成时写下来的。我试图仔细描述实际的命令和错误消息,但可能存在小错误。整个过程与描述的一样。)




(尚未)经过测试(不要相信以下步骤的重要数据),但这里有一个想法,适用于任何增加可用空间并且 mdadm --grow 说“RAID10 布局对于增长操作而言过于复杂”的场景:

  1. 停止md
  2. 备份md中每个分区的前几MiB(假设RAID超块在每个分区的开始附近)。
  3. 擦拭超级区块
  4. 使用分区创建一个 RAID5(或其他 RAID) --assume-clean
  5. 创建 md 的每个分区的快照,例如按照https://gist.github.com/jowagner/b36024636140ddf453c12eaf6e590b5d
  6. 将步骤2中的分区备份恢复为分区的快照
  7. 从快照中组装RAID10
  8. dd 中的所有数据添加到 RAID5。使用 2 个条带大小的最小公倍数可能对性能最好,但任何块大小都应该这样做。前几次读取不会被写入破坏,因为它们来自步骤 5 中写入的写时复制数据。剩余的读取不会被破坏,因为它们与每个分区上的写入保持安全距离(因此这个想法仅限于可用空间增加的场景)。
  9. 停止RAID10
  10. 丢弃快照

这假定一个快照只把对快照的写入重定向到一个COW设备上,并且对原点设备的写入不会触发旧数据的拷贝存储在COW设备上(否则这个解决方案将不实用,因为需要太多的额外空间)。

此外,如果旧RAID的超级块在每个分区的末尾附近,这些数据也需要在步骤3之前备份。计算一个合适的位置来寻找,并计算数据量。我想用几行Python语言,但可能有一个命令行工具可以做到这一点。