![简短版本](https://linux22.com/image/1079523/%E7%AE%80%E7%9F%AD%E7%89%88%E6%9C%AC.png)
问题 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):
- 在其上创建一个新
md(4)
阵列(缺少一个磁盘)。 - 重新创建阵列内容的结构(加密,LVM,分区表,它们的任意组合,无论您喜欢什么)。
- 将数据从现有磁盘复制到新磁盘。
- 重新启动,使用新磁盘。
- 清除旧磁盘的分区表(或将
md(4)
超级块清零)。如有必要,创建所需的分区以匹配新磁盘上的方案。 - 将旧磁盘添加到新阵列。
- 等待阵列成员同步。喝点咖啡。飞往拉丁美洲,亲自采摘咖啡豆。:)(如果你住在在拉丁美洲,请改乘非洲)。
注意:是的,这是与他在回答中描述的技术 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
。让我们检查一下大小:sdy
sdz
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
,无论是分区方式(我上面暗示的)还是磁盘方式),然后必须将数据从现有磁盘移动到该磁盘。
所以:
- 大磁盘(
/dev/sda
)包含数据,数据小于 3001 GB,分区不 - 较小的磁盘
/dev/sdb
被添加到系统中 - 你
/dev/sdb
用分区gdisk
- 从每个相应的分区创建一个数组(
mdadm -C /dev/md2 -l 1 -n 1 /dev/sdb2
) - 在新阵列上创建文件系统
- 复制所有数据,确保您的系统已准备好在 GPT 磁盘上运行,并让 GRUB2 理解其含义(见下文)
- 您将 GPT 分区数据从复制
/dev/sdb
到/dev/sda
- 将“原始”分区添加到
/dev/sda
现有阵列中 - 你等待
/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 ...
和过程会有所不同。不过,我还没有这样做。