简短版本

简短版本

问题 1 - 在您回答“它只需要较小的磁盘”之前,请听我说完。我的 3TB WD Reds 大小为 3001 GB。假设我通过 mdadm 为 sdb1 和 sdc1 设置镜像,该镜像跨越驱动器的 100%。但突然,其中一个驱动器发生故障。替换的是 3TB,重量为 3000 GB。当我放入比阵列上当前存在的驱动器更小的驱动器时会发生什么?我知道使用 3000 而不是 3001 的新阵列,它会将阵列构建为 3000。但就像我说的那样,如果当前阵列为 3001,并且我添加了一个较小的驱动器,该怎么办?它会在重建过程中重新构建自身以使其大小为 3000 GB 吗?

问题 2 - 如果我无法在现有 3001 GB 的情况下向阵列中添加 3000 GB,而只是缩小到 3000...我可以将 3001 的大小稍微缩小一点吗?

问题 3 - 或者,一个更好的主意。如果我将 3TB 驱动器缩小到 2999 GB,会怎么样?这样,无论驱动器是短 1 MB、1 字节还是 10 KB,都没关系,它总是会选择“较小”的驱动器 @ 2999 GB。

答案1

我偶然发现了这个答案,但如果有人好奇,这里有一个由实验支持的答案。

简短版本

附加问题:我可以md(4)使用大小不等的块设备创建 RAID 阵列吗?是的,但 RAID 阵列的大小将为最小的块设备(加上一些用于自身管理的开销)。如果设备大小彼此相差 1% 以内,则会收到警告。

问题 1:我可以向现有 RAID 阵列添加md(4)比当前最小成员更小的设备吗?不,很抱歉。mdadm为了保护您的数据,我们将断然拒绝这样做。

问题 2:您可以调整现有 md 数组的大小吗?是的(请阅读mdadm手册!),但这可能不值得付出努力。您必须备份所有内容,然后调整 RAID 设备的内容大小,然后调整设备本身的大小 — 所有这些都很容易出错、计算错误和其他会造成数据丢失的事情(痛苦的经历)。

不值得冒这个险,也不值得付出努力。如果您有一个新的空白磁盘,下面介绍如何调整其大小,并始终保留一到两份完整的数据副本(假设您有 2 个磁盘 RAID1):

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

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

问题3.如果驱动器少了 1G 怎么办?:)别担心。您的替换驱动器可能会更大。事实上,采用上述策略支付当一个驱动器发生故障时,可以购买更便宜、容量更大的驱动器(或更便宜的升级)。您可以进行渐进式升级。

实验证明

实验装置

首先,让我们伪造一些块设备。我们将使用/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,分别映射到和sdx。让我们检查一下大小:sdysdz

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 块)的循环设备。

使用大小相同的设备创建 RAID 阵列

开始:

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

使用大小不等的设备创建 RAID 阵列

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

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.

好吧,我们收到了警告,但数组已经创建。让我们检查一下大小:

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

最后:向正在运行的阵列添加一个较小的设备

首先,让我们只用 100M 磁盘中的一个来创建一个 RAID1 阵列。阵列会降级,但我们并不关心。我们只想要一个开始数组。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

砰!它不让我们这么做,而且错误非常明显。

答案2

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

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

所以:

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

如果您遵循了所有步骤,您现在应该能够从 mdX 阵列启动到新系统。但是,请准备好救援 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,您还需要使用元数据版本 0.9 创建“BIOS 启动分区”,使用mdadm -e 0 ...和过程会有所不同。不过,我还没有这样做。

相关内容