RAID(mdadm) – 如果驱动器的大小不匹配会怎样?

问题1 – 在回答“只需要较小的磁盘”之前,请快速听到我的声音。 我的3TB WD Reds的尺寸为3001 GB。 假设我通过mdadm为sdb1和sdc1设置了一个镜像,它跨越100%的驱动器。 但突然间,其中一个驱动器发生故障。 更换为3TB,重量为3000 GB。 当我放入一个小于arrays上当前存在的驱动器时会发生什么? 我知道使用3000和3001的新arrays,它会将arrays构建为3000.但就像我说的那样,当前arrays@ 3001和我添加一个更小的驱动器呢? 它在重建期间是否重新构造为3000 GB大小?

问题2 – 如果我不能将3000 GB添加到具有现有3001 GB的arrays中,并且只需缩小到3000 …我可以将3001调整一下吗?

问题3 – 或者,更好的主意。 如果我将3TB驱动器缩小到2999 GB怎么办? 这样,驱动器是否短1 MB,1字节,10 KB,无关紧要,它总是拿起“较小”的驱动器@ 2999 GB。

我错误地看到了这个答案,但万一有人好奇,这是一个由实验支持的答案。

简短版

额外问题:我可以用不等大小的块设备创建一个md(4) RAIDarrays吗? 是的,但RAIDarrays将具有小块设备的大小(加上其自身管理的一些开销)。 如果设备大小不在彼此的1%范围内,则会收到警告。

问题1:我可以在现有的md(4) RAIDarrays中添加小于当前最小成员的设备吗? 不,谢谢。 mdadm将拒绝这样做以保护您的数据。

问题2:您可以调整现有md数组的大小吗? 是的(阅读mdadm manpge!),但这可能不值得。 您必须备份所有内容,然后调整RAID设备的内容大小,然后调整设备本身的大小 – 所有这些都很容易出错,错误计算以及其他会让您的数据损失的事情(痛苦的体验) 。

这不值得冒风险和努力。 如果您有一个新的空白磁盘,这里是如何调整它的大小,并且始终保持所有数据的一到两个副本完整(假设您有2个磁盘RAID1):

  1. 在其上创建一个新的md(4)数组(缺少一个磁盘)。
  2. 重新创建数组内容的结构(加密,LVM,分区表,它的任何组合,无论你的船是什么漂浮)。
  3. 将数据从现有磁盘复制到新磁盘。
  4. 使用新磁盘重新启动。
  5. 擦除旧磁盘的分区表(或将md(4)超级块清零)。 如有必要,创建所需的分区以匹配新磁盘上的方案。
  6. 将旧磁盘添加到新arrays。
  7. 等待arrays成员同步。 喝点咖啡。 飞往拉丁美洲并选择自己的咖啡豆。 :)(如果你住拉丁美洲,请飞往非洲)。

注意:是的,这与他的回答中描述的技术0xC0000022L相同。

问题3.如果驱动器是1G短路怎么办? :)别担心。 机会是你的替代驱动器会更大。 实际上,通过上述策略,只要一个发生故障(或者更便宜的升级),就可以获得更便宜的更大驱动器。 您可以获得渐进式升级。

实validation明

实验装置

首先,让我们伪造一些块设备。 我们将使用/tmp/sdx/tmp/sdy (每个100M)和/tmp/sdz (99M)。

 cd /tmp dd if=/dev/zero of=sdx bs=1M count=100 sudo losetup -f sdx dd if=/dev/zero of=sdy bs=1M count=100 sudo losetup -f sdy dd if=/dev/zero of=sdz bs=1M count=99 # Here's a smaller one! sudo losetup -f sdz 

这将三个文件设置为三个环回块设备: /dev/loop0/dev/loop1/dev/loop2 ,分别映射到sdxsdysdz 。 我们来看看尺寸:

 sudo grep loop[012] /proc/partitions 7 0 102400 loop0 7 1 102400 loop1 7 2 101376 loop2 

正如预期的那样,我们有两个正好100M(102400 KiB = 100 MiB)的循环设备和一个99M(精确99×1024个1K块)。

用相同尺寸的设备制作RAIDarrays

开始:

 sudo mdadm --create -e 1.2 -n 2 -l 1 /dev/md100 /dev/loop0 /dev/loop1 mdadm: array /dev/md100 started. 

检查尺寸:

 sudo grep md100 /proc/partitions 9 100 102272 md100 

这正是我们所期望的:一看mdadm手册就会提醒我们1.2版元数据占用128K:128 + 102272 = 102400.现在让我们将其破坏以准备第二次实验。

 sudo mdadm --stop /dev/md100 sudo mdadm --misc --zero-superblock /dev/loop0 sudo mdadm --misc --zero-superblock /dev/loop1 

用不等大小的设备制作RAIDarrays

这次我们将使用小块设备。

 sudo mdadm --create -e 1.2 -n 2 -l 1 /dev/md100 /dev/loop0 /dev/loop2 mdadm: largest drive (/dev/loop0) exceeds size (101248K) by more than 1% Continue creating array? y mdadm: array /dev/md100 started. 

好吧,我们得到了警告,但是arrays已经完成了。 我们检查一下大小:

 sudo grep md100 /proc/partitions 9 100 101248 md100 

我们得到的是101,248块。 101248 + 128 = 101376 = 99×1024。可用空间是最小设备的空间(加上128K RAID元数据)。 让我们为我们的上一次实验重温一遍:

 sudo mdadm --stop /dev/md100 sudo mdadm --misc --zero-superblock /dev/loop0 sudo mdadm --misc --zero-superblock /dev/loop2 

最后:将较小的设备添加到正在运行的arrays中

首先,让我们用100M磁盘中的一个制作一个RAID1arrays。 arrays会降级,但我们并不在乎。 我们只想要一个已启动的数组。 missing关键字是一个占位符,上面写着“我还没有设备供你使用,现在就启动它,我稍后会添加一个”。

 sudo mdadm --create -e 1.2 -n 2 -l 1 /dev/md100 /dev/loop0 missing 

再次,让我们检查一下大小:

 sudo grep md100 /proc/partitions 9 100 102272 md100 

果然,它比102400块短128K。 添加较小的磁盘:

 sudo mdadm --add /dev/md100 /dev/loop2 mdadm: /dev/loop2 not large enough to join array 

繁荣! 它不会让我们,错误很清楚。

有几种方法可以设置mdX设备。 该方法将使用gdisk (或者如果您更喜欢仅命令行版本的sgdisk )将其分区为GPT。 如果要从arrays引导,请创建“BIOS Boot Partition”,键入代码ef02 。 只有在您想要启动此arrays时才需要这样做,否则无需关心。 然后,创建一个与要添加到arrays的最小磁盘大小相同或更小的分区。 最后但并非最不重要的是,将GPT数据复制到另一个磁盘( gdisk专家菜单,使用x ,然后是u并指定目标设备)。 这是一个破坏性的过程。

应该可以 – 如果文件系统允许它 – 将现有分区的大小调整为更小的值,然后使用相同的方法来复制GPT数据。 然而,这会让你陷入困境。 因为现在你有两个磁盘,但仍然没有mdX设备。 其中一个必须准备为mdX ,无论是分区(我在上面暗示)还是磁盘方式,然后数据必须从现有磁盘移动到那个。

所以:

  1. 大磁盘( /dev/sda )包含数据,数据小于3001 GB,分区不包含
  2. 较小的磁盘/dev/sdb被添加到系统中
  3. 你用gdisk分区/dev/sdb
  4. 你从每个相应的分区创建一个数组( mdadm -C /dev/md2 -l 1 -n 1 /dev/sdb2
  5. 您在新arrays上创建文件系统
  6. 您复制所有数据,确保您的系统准备好运行GPT磁盘并使GRUB2了解其含义(见下文)
  7. 您将GPT分区数据从/dev/sdb复制到/dev/sda
  8. 您将/dev/sda的“原始”分区添加到现有数组中
  9. 等待/proc/mdstat向您显示同步已完成

如果您按照所有步骤操作,现在应该可以从mdXarrays引导到新系统。 但是,为了以防万一,请妥善保管急救CD或PXE引导选项。


GRUB2将无法识别手边的设置。 所以你需要一些“魔力”。 这是一个单行:

 for i in /dev/disk/by-id/md-uuid-*; do DEV=$(readlink $i); echo "(${DEV##*/}) $i"; done|sort|tee /boot/grub/devicemap 

或者让我们更加冗长:

 for i in /dev/disk/by-id/md-uuid-* do DEV=$(readlink $i) echo "(${DEV##*/}) $i" done|sort|sudo tee /boot/grub/devicemap 

这会创建(或覆盖)默认的/boot/grub/devicemap ,并告诉GRUB2在哪里找到每个相应的磁盘。 结果将是这样的列表:

 (md0) /dev/disk/by-id/md-uuid-... (md2) /dev/disk/by-id/md-uuid-... (md3) /dev/disk/by-id/md-uuid-... (md4) /dev/disk/by-id/md-uuid-... 

如果使用旧版GRUB,还需要使用mdadm -e 0 ...创建元数据版本为0.9的“BIOS Boot Partition”,并且过程会有所不同。 不过,我没有这样做过。