ZFS管理手册:第二章RAIDZ
标准奇偶校验RAID
要了解RAIDZ,您首先需要了解基于奇偶校验的RAID等级,如RAID-5和RAID-6。让我们来讨论一下标准的RAID-5数据存储方式。要创建一个RAID-5阵列,您至少需要3个磁盘。在其中的两个磁盘上,数据被条带化。然后计算奇偶校验位,以便将集合中的所有三个条带的异或计算结果为零。最后将奇偶校验写入第三个磁盘。这允许您遇到一个磁盘故障,通过另外两份数据重新计算已丢失的数据。此外,在RAID-5中,阵列中没有单个磁盘专用于保存奇偶校验数据。相反,奇偶校验分布在所有磁盘上。因此,任何磁盘都可能出现故障,而数据仍然可以恢复。
然而,我们有一个问题。假设您已经在RAID-5条带中写入数据,但是在写入奇偶校验之前发生断电的故障。此时会导致您的数据不一致。ZFS的创建者Jeff Bonwick将其称为RAID-5 write hole
。实际上,对于所有基于奇偶校验的RAID阵列来说,无论多小,这都是一个问题。如果存在在不写入奇偶校验位的情况下写入数据块的可能性,那么我们就有可能会遇到“write hole”。糟糕的是,基于软件的RAID没有意识到问题的存在。现在,有通过软件来解决识别奇偶校验与数据不一致的问题,但它们速度很慢,而且不可靠。因此,基于软件的RAID失去了存储管理员的青睐。相反,昂贵(且容易出现故障)的硬件卡,以及在卡上的安装了备用电池,已经变得司空见惯。
还有一个很大的性能问题需要处理。如果写入条带的数据小于条带大小,则必须读取条带的其余部分的数据,并重新计算奇偶校验。这会导致您读取和写入与应用程序无关的数据。与其说读取活动的、运行的数据花费时间,不如说是花大量的时间读取“死的”或旧的数据。因此,昂贵的电池后备NVRAM硬件RAID卡可以对用户隐藏这一延迟,同时NVRAM缓冲区在此条带上工作,直到它被刷新到磁盘。
在这两种情况下,RAID-5 write hole问题,以及将数据写入小于条带大小的磁盘,ZFS的原子事务性质都不喜欢通过硬件解决方案来解决这个问题,而且现有的软件解决方案也没有能解决这种损坏的数据,因此,我们需要重新考虑基于奇偶校验的RAID。
ZFS RAIDZ
现在开始进入了解RAIDZ了。条带宽度不是在创建时静态设置的,而是动态设置的。以事务方式刷新到磁盘的每个数据块都有自己的条带宽度。每个RAIDZ写入都是完整的条带写入。此外,奇偶校验位与条带同时刷新,完全消除了RAID-5写入漏洞。因此,在停电的情况下,您要么拥有最新的数据刷新,要么没有就什么数据都没有。但是,能保证您的磁盘不会不一致。
然而,这其中有一个问题。使用标准化的基于奇偶校验的RAID,逻辑就像“每个磁盘的异或操作都是零”一样简单。对于动态可变条带宽度,例如RAIDZ,这是不起作用的。相反,我们必须调出ZFS元数据来确定每次读取时的RAIDZ拓扑信息。如果您注意观察,您会留意到,文件系统和RAID是相互独立的产品,那么这种情况是不可能的;您的RAID卡对您的文件系统一无所知,反之亦然。这就是ZFS获胜的原因。
此外,因为ZFS知道底层的RAID,所以除非磁盘已满,否则性能不是问题。读取文件系统元数据以构建RAID条带意味着读取数据时,仅需要读取实时、运行的数据,而无需担心读取“死”数据或未分配的空间。因此,在很多方面,文件系统的元数据遍历实际上可以更快。您不需要昂贵的NVRAM来缓冲您的写入,也不需要它在发生RAID write hole时使用备用电池来保证数据的完整。因此,ZFS回到了“廉价磁盘冗余阵列”的旧承诺上。事实上,强烈建议您为ZFS使用便宜的SATA磁盘,而不是昂贵的光纤通道或SAS磁盘。
自愈式RAID
这是使我成为ZFS粉丝的最大原因:ZFS可以检测静默错误,并在运行中修复它们。假设无论出于何种原因,阵列中的某个磁盘上都有坏数据。当应用程序请求数据时,ZFS按照我们刚才了解的那样构造条带,并将每个块与元数据中的校验值和进行比较,这里使用的校验方式为fletcher 4。如果读取条带与校验和不匹配,则ZFS会找到损坏的块,然后读取奇偶校验,并通过组合重建进行修复。然后,它将修复好的数据返回给应用程序。这一切都是在ZFS本身完成的,而不需要特殊硬件的帮助。RAIDZ级别的另一个方面是,如果条带比阵列中的磁盘更长,如果出现磁盘故障,则没有足够的具有奇偶校验的数据可以重建数据。因此,ZFS将条带中的一些数据进行mirror处理,以防止这种情况发生(这里无法理解,翻译可能有误)。
同样,如果您的RAID和文件系统是单独的产品,则它们之间无法很好的沟通,因此不可能检测和修复静默数据错误。现在,让我们构建一些RAIDZ池。与我上一篇文章一样,我将使用5个驱动器/dev/sde、/dev/sdf、/dev/sdg、/dev/sdh和/dev/sdi,它们都是8 GB大小。
RAIDZ-1
RAIDZ-1类似于RAID-5,因为阵列中的所有磁盘都有一个奇偶校验位。无论是更少的磁盘,或更多的磁盘,都如上图所以,它的条带宽度是可变的,可以准确的覆盖阵列中磁盘的块大小。它允许一个磁盘出现故障但是依然能保证数据的完整。但是有两个磁盘故障都会导致数据的丢失。至少需要使用3个磁盘才能组成一个RAIDZ-1。存储的容量将是阵列中的磁盘数量乘以最小磁盘的存储空间,然后减去一个磁盘用于奇偶校验存储(关于zpool存储大小,我将在另一篇文章中介绍)。可以理解为:(n-1)*min(disk_size),此处创建的阵列的大小将是16GB。
要创建RAIDZ-1的zpool,我们使用“raidz1”VDEV,在本例中仅使用3个驱动器:
# 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 destroy tank
RAIDZ-2
RAIDZ-2与RAID-6的相似之处在于,阵列中的所有磁盘都有一个双奇偶校验位。无论是更少的磁盘,或更多的磁盘,都如上图所以,它的条带宽度是可变的,可以准确的覆盖阵列中磁盘的块大小。它允许两个磁盘出现故障但是依然能保证数据的完整。但是有三个磁盘故障都会导致数据的丢失。至少需要使用4个磁盘才能组成一个RAIDZ-2。存储的容量将是阵列中的磁盘数量乘以最小磁盘的存储空间,然后减去两个磁盘用于奇偶校验存储(关于zpool存储大小,我将在另一篇文章中介绍)。可以理解为:(n-2)*min(disk_size),此处创建的阵列的大小将是16GB。
要创建RAIDZ-2的zpool,我们使用“raidz2”VDEV,在本例中仅使用4个驱动器:
# 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
在继续下面的步骤之前,我们先把这个池删掉:
# zpool destroy tank
RAIDZ-3
RAIDZ-3没有标准的RAID级别可供比较。但是,它是RAIDZ-1和RAIDZ-2的逻辑的延续,因为它有一个三重奇偶校验位分布在阵列中的所有磁盘上。无论是更少的磁盘,或更多的磁盘,都如上图所以,它的条带宽度是可变的,可以准确的覆盖阵列中磁盘的块大小。它允许三个磁盘出现故障但是依然能保证数据的完整。但是有四个磁盘故障都会导致数据的丢失。至少需要使用5个磁盘才能组成一个RAIDZ-3。存储的容量将是阵列中的磁盘数量乘以最小磁盘的存储空间,然后减去两个磁盘用于奇偶校验存储(关于zpool存储大小,我将在另一篇文章中介绍)。可以理解为:(n-3)*min(disk_size),此处创建的阵列的大小将是16GB。
要创建RAIDZ-3的zpool,我们使用“raidz3”VDEV,在本例中仅使用5个驱动器:
# 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
混合RAIDZ
不幸的是,基于奇偶校验的RAID性能并不会带好,特别是当您在一个条带中有多个磁盘时(比如48个磁盘的JBOD)。为了加快速度,可以考虑将单个大型RAIDZ VDEV切成多个RAIDZ VDEV。这将耗费一部分本将用于存储数据的磁盘空间,但可以极大地提高性能。当然,与以前的RAIDZ VDEV一样,条带宽度在每个嵌套的RAIDZ VDEV中是可变的。对于每个RAIDZ级别,您可以在每个VDEV中丢失多达相同数量的磁盘。因此,如果您有三个RAIDZ-1 VDEV的条带,那么您总共可能会遇到三个磁盘故障,每个VDEV可以损失一个磁盘。可用空间的计算方法与此类似,在此示例中,由于每个VDEV中的都需要存储奇偶校验信息,所以有三个硬盘的空间会被校验信息所占用。
为了说明这一概念,假设我们有一个12个磁盘的存储服务器,并且我们希望在最大化条带性能的同时损失尽可能少的磁盘。因此,我们将创建4个RAIDZ-1 VDEV,每个VDEV有3个磁盘。这将有4个磁盘用于存储娇艳信息,但也会使我们能够承受4个磁盘故障,并且跨4个VDEV的条带将提高性能。
要创建一个具有4个RAIDZ-1 VDEV的zpool,我们在命令中使用了4次“raidz1”。
# 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 VDEV。正如在上一篇文章中提到的,ZFS的条带是可以跨VDEV的。因此,这个设置实质上是RAIDZ-1+0。每个RAIDZ-1 VDEV将收到发送到池的1/4的数据,然后每个条带化数据段将跨每个VDEV中的磁盘进一步条带化。嵌套的VDEV是在池被大量碎片化之后很久仍能保持良好性能的一种很好的方法。
关于RAIDZ的一些最后想法
关于何时使用RAIDZ-1/2/3以及何时不使用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的每个磁盘不超过1 TB,RAIDZ-2的每个磁盘不超过2 TB,RAIDZ-3的每个磁盘不超过3 TB。对于超过这些值的大小,您应该使用带条带的2路或3路镜像。这些说法是否有任何有效性,我不能说。但是,我可以告诉您,在磁盘数量较少的情况下,您应该使用能够弥补您的缺点的RAID级别。在4磁盘RAID阵列中,如我上面所述,计算多个奇偶校验位可能会降低性能。此外,我最多可能遇到两个磁盘故障(如果使用的是RAID-1+0或RAIDZ-2)。RAIDZ-1介于两者之间,我可以在遭受磁盘故障的同时仍然保持良好的性能水平。如果我假设阵列中有12个磁盘,那么RAIDZ-1+0或RAIDZ-3可能会更合适,因为遭受多个磁盘故障的可能性会增加。
最终,您需要了解存储问题并对磁盘进行基准测试。用他们来创建各种等级的阵列,并使用IOZone 3等实用程序对阵列进行基准测试和压力测试。您知道要在磁盘上存储什么数据。您知道要将磁盘安装到哪种硬件中,这将取决于你想要它的性能能达到哪个程度。如果你话很多时间去考虑这些,你也会做出正确的决定。也许还会有一些“最佳实践”,但它们只适用于您的具体情况。
最后,在性能方面,无论是读取还是写入,mirror总是优于RAIDZ。此外,RAIDZ-1将超过RAIDZ-2,而RAIDZ-2将超过RAIDZ-3。需要计算的奇偶校验位越多,读取和写入数据所需的时间就越长。当然,您始终可以向VDEV添加条带化,以最大限度地提高某些性能。嵌套的RAID级别(如RAID-1+0)被认为是“RAID级别中的凯迪拉克”,因为您可以灵活地丢失没有奇偶校验的磁盘,以及从条带中获得的吞吐量。因此,简而言之,从最快到最慢,您的非嵌套RAID级别将执行如下操作:
- RAID-0 (最快)
- RAID-1
- RAIDZ-1
- RAIDZ-2
- RAIDZ-3 (最慢)