ZFS系列(二)ZAIDZ

介绍RAIDZ之前,首先需要我们对标准的RAID有一个了解,知道它有什么问题。如果标准的RAID很完美,那么就不需要再搞一个RAIDZ出来了。
本文主要介绍标准的RAID存在什么问题,然后介绍RAIDZ有什么特点,以及几种常见的RAIDZ和如何创建RAIDZ的zpool。

标准的基于奇偶检验的RAID

为了理解RAIDZ,首先需要理解基于奇偶检验的RAID级别,比如RAID5和RAID6。先看一下标准RAID-5的布局。RAID-5至少需要3块硬盘。在2个硬盘上,数据被条带化。然后计算一个奇偶校验位,其结果是集合中所有三个条带的异或,然后将奇偶校验写入磁盘。这种情况允许一个磁盘故障,并可以重新计算恢复数据。此外,在RAID-5中,阵列中没有单个硬盘专门用于校验数据。而是把奇偶校验分布在所有的磁盘上。因此,任何磁盘都可能发生故障,但数据仍然可以恢复。
然而,还是有个问题。假设在RAID-5分条中写入数据,但在写入奇偶校验之前发生了断电。您现在有了不一致的数据。ZFS的创建者Jeff Bonwick将此称为“RAID-5 write hole”。实际上,对于所有基于奇偶校验的RAID阵列来说,无论多小,这都是一个问题。如果存在写入数据块而不写入奇偶位的任何可能性,那么我们就有“write hole”。糟糕的是,基于软件的RAID不知道存在这个问题。现在,有一些软件可以识别奇偶校验与数据不一致,但它们很慢并且也不可靠。因此,基于软件的RAID已经不再受到存储管理员的青睐。相反,昂贵(而且容易发生故障)的且带有备份电源的硬件卡,已经变得司空见惯。

除了上面的问题,还有一个很大的性能问题需要处理。如果正在写入分条的数据小于分条的大小,则必须从分条的其余部分读取数据,并重新计算奇偶校验。这将导致您读写与应用程序无关的数据。
不是只读取活的、运行的数据,而是花大量时间读取“死的”或旧的数据。因此,昂贵的电池支持的NVRAM硬件RAID卡可以向用户隐藏这个延迟,然而NVRAM缓冲区只有在这个条带数据被刷到磁盘前有效。

由于有这两种缺陷:RAID-5写入漏洞和将数据写入小于条带大小的磁盘,ZFS的原子事务性质不喜欢硬件解决方案,因为这是不可能的,也不喜欢现有的软件解决方案,因为它可能导致数据损坏。因此,需要重新考虑基于奇偶校验的RAID。

ZFS RAIDZ

RAIDZ与RAID5不同,RAIDZ不是在创建时静态设置条带宽度,而是动态设置条带宽度。每个以事务方式刷新到磁盘的块都有自己的条带宽度。每次RAIDZ写都是一次全分条写。并且,奇偶校验位与条带同时刷新,完全消除RAID-5“write hole”问题。所以,在停电的情况下,你要么有最新的数据刷新,要么没有。但是,磁盘不会是不一致的。

然而,这里有一个陷阱。使用标准化的基于奇偶校验的RAID,逻辑就像“每个磁盘XORs为零”一样简单。对于动态可变条带宽度(如RAIDZ),这是不行的。相反,我们必须提取ZFS元数据来确定每次读取时的RAIDZ条带大小等信息。如果您注意的话,您会注意到,如果文件系统和RAID是独立的产品,那么这种情况是不可能的;您的RAID卡不知道您的文件系统,反之亦然。这就是ZFS胜出的原因。

而且,由于ZFS了解底层RAID,除非磁盘已满,否则性能不会成为问题。读取文件系统元数据以构建RAID分条意味着只读取实时运行的数据。不需要担心读取“死”数据或未分配的空间。因此,文件系统的元数据遍历在许多方面实际上可以更快。您不需要昂贵的NVRAM来缓冲写操作,也不需要它作为RAID “write hole”时的电池备份。因此,ZFS又回到了“廉价磁盘冗余阵列”的老承诺。事实上,强烈建议您使用便宜的SATA磁盘,而不是昂贵的光纤通道或用于ZFS的SAS磁盘。

有自愈能力的RAID

假设由于某种原因,阵列中的磁盘上有坏数据。ZFS可以检测无声错误,并动态地修复它们。这就是我成为ZFS粉丝的最大原因。当应用程序请求数据时,ZFS构造我们上面了解到的条带,并将每个块与元数据中的默认校验值(当前为fletcher4)进行比较。如果读到的条带校验值不匹配,ZFS会找到损坏的块,然后读取奇偶校验,并通过组合重构修复它。然后它将修复的数据返回给应用程序。这一切都是在ZFS本身中完成的,无需特殊硬件的帮助。

RAIDZ级别的另一个方面是,如果条带比阵列中的磁盘长,如果出现磁盘故障,则没有足够的具有奇偶校验的数据可以重建数据。因此,ZFS将在条带中镜像一些数据,以防止这种情况发生。

同样,如果您的RAID和文件系统是独立的产品,那么它们并不知道彼此,因此检测和修复静默数据错误是不可能的。因此,解决了RAIDZ的基本概念问题之后,让我们构建一些RAIDZ池。和我之前的文章一样,我将使用5个USB u盘/dev/sde, /dev/sdf, /dev/sdg, /dev/sdh和/dev/sdi,它们的大小都是8GB。

RAIDZ-1

RAIDZ-1类似于RAID-5,它有一个分布在阵列中所有磁盘上的奇偶校验位。条带宽度是可变的,可以覆盖阵列中磁盘的某一确切宽度,可以覆盖更少的磁盘,也可以覆盖更多的磁盘,如上面的图所示。RAIDZ-1能容忍一个磁盘损坏而不丢失数据。2个硬盘故障,可能导致数据丢失。RAIDZ-1要求硬盘数不少于3块。存储的容量将是数组中的磁盘数量乘以最小磁盘的存储容量,减去一个奇偶校验磁盘(我将在另一篇文章中讨论zpool存储容量大小的注意事项)。所以在我的例子中,我应该有大约16GB的可用磁盘。
为了设置一个带有raidz1的zpool,我们使用“raidz1”VDEV,在本例中只使用3个USB驱动器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# zpool create tank raidz1 sde sdf sdg
# zpool status tank
pool: pool
state: ONLINE
scan: none requested
config:

NAME STATE READ WRITE CKSUM
pool ONLINE 0 0 0
raidz1-0 ONLINE 0 0 0
sde ONLINE 0 0 0
sdf ONLINE 0 0 0
sdg ONLINE 0 0 0

errors: No known data errors

继续之前清理刚创建的zpool
1
zpool destroy tank

RAIDZ-2

RAIDZ-2与RAID-6相似,在阵列中的所有磁盘上都有一个双奇偶校验位。条带宽度是可变的,可以覆盖阵列中磁盘的某一确切宽度,可以覆盖更少的磁盘,也可以覆盖更多的磁盘。RAIDZ-2能容忍最多两盘故障。如果出现3盘故障,将导致数据丢失。RAIDZ-2至少需要4块硬盘。
存储的容量将是阵列中的磁盘数量乘以最小磁盘的存储容量,减去两个奇偶校验磁盘。所以在我的例子中,我应该有大约16GB的可用磁盘。
为了使用RAIDZ-2设置zpool,我们使用“raidz2”VDEV:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# zpool create tank raidz2 sde sdf sdg sdh
# zpool status tank
pool: pool
state: ONLINE
scan: none requested
config:

NAME STATE READ WRITE CKSUM
pool ONLINE 0 0 0
raidz2-0 ONLINE 0 0 0
sde ONLINE 0 0 0
sdf ONLINE 0 0 0
sdg ONLINE 0 0 0
sdh ONLINE 0 0 0

errors: No known data errors

清理环境
1
zpool destroy tank

RAIDZ-3

RAIDZ-3没有可以与之比较的标准化RAID级别。但是,它是RAIDZ-1和RAIDZ-2的逻辑延续,因为在阵列中的所有磁盘上都有一个三重奇偶校验位。条带宽度是可变的,可以覆盖阵列中磁盘的确切宽度,也可以覆盖更少的磁盘,也可以覆盖更多的磁盘,如上图所示。RAIDZ-3能容忍3盘故障。4块硬盘故障,会导致数据丢失。 RAIDZ-3至少需要5块硬盘。存储的容量将是阵列中的磁盘数量乘以最小磁盘的存储,减去3个奇偶校验磁盘。所以在我的例子中,我应该有大约16GB的可用磁盘。
为了使用RAIDZ-3设置zpool,我们使用“raidz3”VDEV:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# zpool create tank raidz3 sde sdf sdg sdh sdi
# zpool status tank
pool: pool
state: ONLINE
scan: none requested
config:

NAME STATE READ WRITE CKSUM
pool ONLINE 0 0 0
raidz3-0 ONLINE 0 0 0
sde ONLINE 0 0 0
sdf ONLINE 0 0 0
sdg ONLINE 0 0 0
sdh ONLINE 0 0 0
sdi ONLINE 0 0 0

errors: No known data errors

清理环境
1
zpool destroy tank

混合RAIDZ

不幸的是,基于奇偶校验的RAID速度很慢,特别是在单个条带中有许多磁盘时(例如48磁盘的JBOD)。为了提高速度,将单个大型RAIDZ VDEV分割为多个RAIDZ VDEV的条带可能不是一个坏主意。这将消耗您可用的磁盘空间来存储,但可以极大地提高性能。当然,与前面的RAIDZ VDEV一样,每个嵌套的RAIDZ VDEV中的条带宽度是可变的。对于每个RAIDZ级别,您可以在每个VDEV中丢失最多这么多磁盘。因此,如果您有一个由三个RAIDZ-1 VDEV组成的条带,那么您总共可以容忍三个磁盘故障,每个VDEV一个磁盘故障。可用空间的计算方法类似。在本例中,由于每个VDEV中的奇偶校验存储,您将减去三个磁盘空间(因为用来存储校验数据了)。

为了说明这个概念,让我们假设我们有一个12磁盘的存储服务器,我们希望在最大化条带性能的同时损失尽可能少的磁盘。因此,我们将创建4个RAIDZ-1 vdev,每个RAIDZ-1包含3个磁盘。这将使占用我们4个可用于存储数据的磁盘(用于存储校验数据),但它也将使我们能够承受4个磁盘故障,并且跨4个vdev的条带将会提高性能。

为了设置一个带有4个raidz1 VDEV的zpool,我们在命令中使用了4次“raidz1”VDEV。注意,为了清晰起见,我强调了什么时候在命令中输入”raidz1”:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# zpool create tank raidz1 sde sdf sdg raidz1 sdh sdi sdj raidz1 sdk sdl sdm raidz1 sdn sdo sdp
# zpool status tank
pool: pool
state: ONLINE
scan: none requested
config:

NAME STATE READ WRITE CKSUM
pool ONLINE 0 0 0
raidz1-0 ONLINE 0 0 0
sde ONLINE 0 0 0
sdf ONLINE 0 0 0
sdg ONLINE 0 0 0
raidz1-1 ONLINE 0 0 0
sdh ONLINE 0 0 0
sdi ONLINE 0 0 0
sdj ONLINE 0 0 0
raidz1-2 ONLINE 0 0 0
sdk ONLINE 0 0 0
sdl ONLINE 0 0 0
sdm ONLINE 0 0 0
raidz1-3 ONLINE 0 0 0
sdn ONLINE 0 0 0
sdo ONLINE 0 0 0
sdp ONLINE 0 0 0

errors: No known data errors

注意,现在有四个RAIDZ-1 VDEVs。正如在之前的文章中提到的,ZFS条带跨多个VDEVs。因此,这个设置本质上是RAIDZ-1+0。每个RAIDZ-1 VDEV将接收发送到池的数据的1/4,然后每个条带块将在每个VDEV中的磁盘上进一步条带化。嵌套的VDEVs可以在池被大规模分段之后很长一段时间保持良好的性能。

清理环境

1
zpool destroy tank

关于RAIDZ的一些想法

关于何时使用RAIDZ-1/2/3,何时不使用,存在各种建议。有人说RAIDZ-1和RAIDZ-3应该使用奇数个硬盘。RAIDZ-1至少3块硬盘,且不超过7块硬盘;RAIDZ-3可以7用块盘,且不超过15块硬盘。RAIDZ-2应该使用偶数个磁盘,从6个磁盘开始,不能超过12个。这是为了确保实际写入数据的磁盘数量是偶数,并最大化阵列的性能。

如果超出这些建议,我个人会使用RAID-1+0设置。这很大程度上是由于重建数据所需要的时间(称为“resilvering”——后面会有文章介绍这个)。由于计算奇偶校验位非常昂贵,因此与RAID-1+0相比,RAIDZ数组中的磁盘越多,该操作的成本就越高。

此外,我还看到了关于磁盘大小的建议,说RAIDZ-1每个磁盘不超过1TB, RAIDZ-2每个磁盘不超过2TB, RAIDZ-3每个磁盘不超过3TB。对于超过这些值的大小的,应该使用带条纹的2路或3路镜像。我不能确定这些说法是否有效。但是,我可以告诉您,在磁盘数量较少的情况下,您应该使用能够适应您的缺点的RAID级别。在4盘RAID阵列中,如前所述,计算多个奇偶校验位会降低性能。此外,4盘RAID最多能容忍两个磁盘故障(如果使用RAID-1+0或RAIDZ-2)。RAIDZ-1介于两者之间,在这种情况下,可以容忍单个磁盘故障,同时仍然保持良好的性能水平。如果数组中有12个磁盘,那么可能更适合RAIDZ-1+0或RAIDZ-3,因为出现多个磁盘故障的几率会增加。

最后,您需要理解你的存储问题并对你的硬盘进行基准测试。将它们放在不同的RAID配置中,并使用IOZone 3等工具对阵列进行基准测试和压力测试。你需要知道要在磁盘上存储什么数据。你要知道磁盘安装在什么类型的硬件上。你要知道你需要什么样的性能表现。这是你的决定,如果你花时间做研究、作业和调查,你会得出正确的决定。可能有“最佳实践”,但它们只适用于某种具体情况。总之,就是说每个人需要根据自己的性能需求,硬盘性能和硬件能力来选择最适合他们自己的RAID配置

最后,在性能方面,镜像的读和写总是优于RAIDZ级别。此外,RAIDZ-1将优于RAIDZ-2,而RAIDZ-2将优于RAIDZ-3。需要计算的奇偶校验位越多,读取和写入数据所需的时间就越长。当然,您总是可以在VDEVs中添加条带以最大化某些性能。嵌套的RAID级别(如RAID-1+0)被认为是“RAID级别中的凯迪拉克”,这是由于可以在没有奇偶校验的情况下丢失磁盘的灵活性和从条带获得的吞吐量。因此,简而言之,从最快到最慢的排序如下:

  • RAID-0 (fastest)
  • RAID-1
  • RAIDZ-1
  • RAIDZ-2
  • RAIDZ-3 (slowest)

总结

RAIDZ尽管和RAID5有很多地方类似,但是RAIDZ并不是RAID5.
RAID5的缺陷:

  1. RAID5最显著的缺点就是“write hole”,因为他无法提供任何安全的机制保证写校验码的时候不出现故障。而如果此时断电,那么将造成parity是错误的,当然后期利用这个错误的parity更新的新的数据块将更是错误的。而此时用户并不知道。
  2. RAID5另一个问题是性能问题。如果正在写入分条的数据小于分条的大小,则必须从分条的其余部分读取数据,并重新计算奇偶校验。这将导致读写与应用程序无关的数据。

RAIDZ具有两个显著的特点
特点一
避免了读旧数据-修改parity-写数据的RAID写磁盘模式,而是通过full stripe write的方式完成写数据操作。这样一次性写入 保证了即使断电,也不会出现不一致的状况。要么写成功,要么什么都没做。
特点二
就是动态条带化的特点。抛弃的传统的stripe都是固定长度的特点。

参考资料

https://pthree.org/2012/12/05/zfs-administration-part-ii-raidz/

如果你觉得本文对你有帮助,欢迎打赏