我想构建一个 NAS,使用 mdadm 进行 RAID,使用 btrfs 进行 bitrot 检测。我有一个相当基本的设置,将 3 个 1TB 磁盘与 mdadm 组合成 RAID5,然后在其上添加 btrfs。
我知道 mdadm 无法修复 bitrot。它只能告诉我何时出现不匹配,但不知道哪些数据正确,哪些数据有故障。当我在模拟 bitrot 后告诉 mdadm 修复我的 md0 时,它总是重建奇偶校验。Btrfs 使用校验和,因此它知道哪些数据有故障,但由于看不到奇偶校验,因此无法修复数据。
但是,我可以运行 btrfs 清理并读取系统日志以获取与校验和不匹配的数据的偏移量。然后,我可以将此偏移量转换为磁盘和该磁盘上的偏移量,因为我知道 md0 的数据起始偏移量 (2048 * 512)、块大小 (512K) 和布局 (左对称)。布局意味着在我的第一个层中,奇偶校验位于第三个磁盘上,第二个层位于第二个磁盘上,第三个层位于第一个磁盘上。
结合所有这些数据和一些关于磁盘格式的 btrfs 知识,我可以准确计算出哪个磁盘的哪个块有故障。但是,我找不到方法告诉 mdadm 修复这个特定的块。
我已经编写了一个脚本,使用 dd 命令交换奇偶校验和故障块,然后使用 mdadm 启动修复,然后将它们交换回来,但这不是一个好的解决方案,我真的希望 mdadm 将此扇区标记为坏扇区并且不再使用它。由于它开始腐烂,很有可能它会再次这样做。
我的问题是:有什么方法可以告诉 mdadm 修复单个块(不是奇偶校验)甚至可能将磁盘扇区标记为坏扇区?也许会造成读取 io 错误?
(我知道 ZFS 可以自行完成所有这些操作,但我不想使用 ECC 内存)
编辑:这问题/答案是关于 btrfs RAID6 不稳定的原因以及 ZFS 更稳定/更易用的原因。这并没有解决我关于如何使用 mdadm 修复单个已知故障块的问题。
答案1
我找不到方法来告诉 mdadm 修复这个特定的块。
这是因为当出现静默数据损坏时,md 没有足够的信息来知道哪个块被静默损坏了。
我邀请你阅读我的问题 #4 的答案(“为什么md
继续使用具有无效数据的设备?”)在这里,进一步详细地解释了这一点。
更糟糕的是,你提议的布局如果奇偶校验块遭受静默数据损坏,则上方的 Btrfs 层无法看到它! 当具有相应数据块的磁盘发生故障并且您尝试更换它时,md 将使用损坏的奇偶校验并不可逆转地损坏您的数据。只有当该磁盘发生故障时,Btrfs 才会识别出损坏,但您已经丢失了数据。
这是因为,除非阵列降级,否则 md 不会从奇偶校验块读取。
那么,有什么方法可以告诉 mdadm 修复单个块(不是奇偶校验)甚至可能将磁盘扇区标记为坏扇区吗?也许会造成读取 io 错误?
对于硬盘自己发现的坏道,md 可以轻松应对,因为坏道已经被 md 识别了。
从技术上来说,你可以用 来制造一个坏扇区hdparm --make-bad-sector
,但是你如何知道哪个磁盘上的块受到了静默数据损坏的影响呢?
考虑这个简化的例子:
奇偶校验公式:PARITY = DATA_1 + DATA_2
+--------+--------+--------+
| DATA_1 | DATA_2 | PARITY |
+--------+--------+--------+
| 1 | 1 | 2 | # OK
+--------+--------+--------+
现在让我们用以下值悄悄破坏每个块3
:
+--------+--------+--------+
| DATA_1 | DATA_2 | PARITY |
+--------+--------+--------+
| 3 | 1 | 2 | # Integrity failed – Expected: PARITY = 4
| 1 | 3 | 2 | # Integrity failed – Expected: PARITY = 4
| 1 | 1 | 3 | # Integrity failed – Expected: PARITY = 2
+--------+--------+--------+
如果你没有第一个表可以查看,你怎么知道哪个块被损坏了?
你无法确定。
这就是 Btrfs 和 ZFS 都对块进行校验的原因。这需要更多磁盘空间,但这些额外信息可以让存储系统找出哪个块存在问题。
每当您读取 RAID-Z 块时,ZFS 都会将其与校验和进行比较。如果数据磁盘未返回正确答案,ZFS 会读取奇偶校验,然后进行组合重建以找出哪个磁盘返回了坏数据。
要在 md 上使用 Btrfs 执行此操作,您必须尝试重新计算每个块,直到 Btrfs 中的校验和匹配,这是一个耗时的过程,并且没有向用户/脚本公开简单的界面。
我知道 ZFS 可以自行完成所有这些操作,但我不想使用 ECC 内存
ZFS 和 Btrfs over md 都不依赖 ECC 内存,甚至不知道 ECC 内存的存在。ECC 内存仅能捕获内存中的静默数据损坏,因此它与存储系统无关。
我之前曾推荐过在 RAID-5 和 RAID-6 中使用 ZFS,而不是 Btrfs(分别类似于 ZFS RAID-Z 和 RAID-Z2)。Btrfs 通过 mdadm raid6?和当 ATA 停止响应时,md RAID 中的设备发生故障但我想借此机会概述一下 ZFS 的更多优点:
- 当 ZFS 检测到静默数据损坏时,它会立即自动纠正,无需任何人工干预。
- 如果您需要重建整个磁盘,ZFS 将仅“重新镀银”实际数据,而不是不必要地在整个块设备上运行。
- ZFS 是逻辑卷和文件系统的一体化解决方案,这使得它的管理比 md 上的 Btrfs 更简单。
- RAID-Z 和 RAID-Z2 可靠且稳定,不同于
- md RAID-5/RAID-6 上的 Btrfs 仅提供对无声损坏数据块的错误检测(此外,无声损坏的奇偶校验块可能在为时已晚之前都无法检测到),并且没有简单的方法来进行错误纠正,并且
- Btrfs RAID-5/RAID-6,其“存在多个导致数据丢失的严重漏洞“。
- 如果我悄悄损坏了 ZFS RAID-Z2 的整个磁盘,我不会丢失任何数据,而在 md RAID-6 上,我实际上丢失了 455,681 个 inode。
答案2
我找到了一种为 mdadm 创建读取错误的方法。
使用 dmsetup 您可以从表创建逻辑设备。
通过加载指定每个扇区(512 字节)目标的表来创建设备
从:手册页
在这些表中,您可以指定应返回 IO 错误的偏移量,例如:
0 4096 linear /dev/sdb 0
4096 1 error
4097 2093055 linear /dev/sdb 4097
这将创建一个设备(1GB),其错误位于偏移量 4096*512 处。