ZFS系列补充(一)图解ZIL


背景

在和同事一起散步的时候,讨论了异步写入和ZIL内容究竟是什么的问题。然而,在并没有真正讨论过ZIL的内容是什么之前,说实话,我自己也没有完全理解它。Andrew Kuhnhausen澄清了这一点。所以,根据我们在散步时的讨论,以及白板上的一些漂亮的图表,我将在这里给你们详细说明。

让我们从头说起。ZFS的行为更像ACID兼容的RDBMS,而不是传统的文件系统。它的写入是事务,这意味着没有部分写入,它们是完全原子的,这意味着您要么得到全部,要么什么都得不到。无论写操作是同步的还是异步的,都是如此。所以,最好的情况是你有所有的数据。最坏的情况是您错过了最后一次事务性写入,并且您的数据是5秒前的(默认情况下)。那么,让我们也看看这些情况——同步写和异步写。对于同步,我们将考虑是否使用单独的日志记录设备(SLOG)进行写操作。

ZIL功能

ZIL的主要也是唯一的功能是在发生故障时重放丢失的事务。当发生断电、崩溃或其他灾难性故障时,RAM中的挂起事务可能没有提交到较慢的磁盘。因此,当系统恢复时,ZFS将注意到丢失的事务。此时,将读取ZIL以重放这些事务,并将数据提交到稳定存储。
当系统启动并正常运行时,ZIL永远不会被读取,它只写入。您可以通过以下操作验证这一点(假设您的系统中有SLOG):打开两个终端。在一个终端上运行IOZone基准测试。做以下事情:

1
$ iozone -ao

这将运行一系列测试,以查看磁盘的性能。当这个基准测试运行时,在另一个终端中,以root用户的身份运行以下命令:

1
# zpool iostat -v 1

这将清楚地告诉您,当ZIL驻留在一个SLOG上时,SLOG设备只被写入。你永远不会在read列中看到任何数字。这是因为不会读取ZIL,除非需要在崩溃时重放事务。下面是其中一秒钟的文字说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
                                                            capacity     operations    bandwidth
pool alloc free read write read write
------------------------------------------------------- ----- ----- ----- ----- ----- -----
pool 87.7G 126G 0 155 0 601K
mirror 87.7G 126G 0 138 0 397K
scsi-SATA_WDC_WD2500AAKX-_WD-WCAYU9421741-part5 - - 0 69 0 727K
scsi-SATA_WDC_WD2500AAKX-_WD-WCAYU9755779-part5 - - 0 68 0 727K
logs - - - - - -
mirror 2.43M 478M 0 8 0 108K
scsi-SATA_OCZ-REVODRIVE_XOCZ-6G9S9B5XDR534931-part1 - - 0 8 0 108K
scsi-SATA_OCZ-REVODRIVE_XOCZ-THM0SU3H89T5XGR1-part1 - - 0 8 0 108K
mirror 2.57M 477M 0 7 0 95.9K
scsi-SATA_OCZ-REVODRIVE_XOCZ-V402GS0LRN721LK5-part1 - - 0 7 0 95.9K
scsi-SATA_OCZ-REVODRIVE_XOCZ-WI4ZOY2555CH3239-part1 - - 0 7 0 95.9K
cache - - - - - -
scsi-SATA_OCZ-REVODRIVE_XOCZ-6G9S9B5XDR534931-part5 26.6G 56.7G 0 0 0 0
scsi-SATA_OCZ-REVODRIVE_XOCZ-THM0SU3H89T5XGR1-part5 26.5G 56.8G 0 0 0 0
scsi-SATA_OCZ-REVODRIVE_XOCZ-V402GS0LRN721LK5-part5 26.7G 56.7G 0 0 0 0
scsi-SATA_OCZ-REVODRIVE_XOCZ-WI4ZOY2555CH3239-part5 26.7G 56.7G 0 0 0 0
------------------------------------------------------- ----- ----- ----- ----- ----- -----

ZIL应该总是放在非易失性的稳定存储! 您希望您的数据在断电时保持一致。将您的ZIL放在由TMPFS、RAMFS或RAM驱动器构建的SLOG上,而这些驱动器不是电池备份的,这意味着您将丢失任何挂起的事务,当然这并不意味着你会有损坏的数据。这只意味着你将拥有旧数据。在易失性存储上使用ZIL,发生故障时您将永远无法获得在写到稳定存储时挂起的新数据。取决于您的服务器有多忙,这可能是一个大问题。来自英特尔或OCZ的ssd是一种很好的廉价方法,可以获得快速、低延迟的SLOG,在断电时也是可靠的。

没有SLOG的同步写

当您没有SLOG时,应用程序只与RAM和普通磁盘进行交互。正如前面所讨论的,可以将ZFS Intent LOG (ZIL)看作是驻留在慢速磁盘上的文件。当应用程序需要进行同步写操作时,写操作的内容将被发送到应用程序当前所在的RAM,并被发送到ZIL。 因此,同步写入的数据块在这个时刻需要去两个地方——RAM和ZIL。一旦数据被写入到ZIL,盘片磁盘就会向应用程序发送一个确认,让它知道它拥有数据,此时数据就会从RAM刷新到较慢的磁盘。

然而,情况并非总是如此。在磁盘速度较慢的情况下,ZFS实际上可以立即将事务组(TXG)存储在磁盘上,并在ZIL中使用指针指向磁盘上的位置的。当磁盘返回ZIL包含指向数据的指针时,写入TXG将在RAM中关闭,并为将来的事务打开ZIL中的空间。因此,本质上,您可以将TXG SYNCHRONOUS以三种方式进行写提交:
(1)所有数据块同步写入RAM ARC和ZIL。
(2)所有数据块都同步写入RAM ARC和VDEV,指针指向写到ZIL的数据块。
(3)所有的数据块都被同步地写入磁盘,而ZIL则完全被忽略。
在下图中,我试图捕捉第一个过程的简化视图。标记为1的粉色箭头表示应用程序将其数据提交给RAM和ZIL。从技术上讲,应用程序已经在RAM中运行了,但我把它拿出来是为了让图像更清晰一些。在块被提交到RAM后,磁盘返回写入ZIL的ACK,标记为2号绿色箭头。最后,ZFS将数据块从RAM中刷到磁盘,标记为三号的灰色箭头说明了这一点。

带有SLOG的同步写

如前面的文章所述,SLOG的优点是能够使用低延迟、快速地将ACK发送回应用程序。注意,ZIL现在驻留在SLOG上,而不再驻留在盘上。SLOG将捕获所有同步写操作(至少是那些用O_SYNC和fsync(2)调用的操作)。与盘片磁盘一样,ZIL将包含应用程序试图提交到稳定存储的数据块。然而,作为一个快速的SSD或NVRAM驱动器,写完ZIL后,SLOG会ACK,此时ZFS会将数据从RAM中刷新到慢盘中。

注意,ZFS没有将数据从ZIL刷新到磁盘。这就是最初让我困惑的地方。数据从RAM刷新到磁盘。与ACID兼容的RDBMS一样,ZIL仅用于在发生故障和数据丢失时重放事务。否则,永远不会从ZIL读取数据。所以写操作根本没有改变。只有ZIL的位置发生了变化。否则,操作完全相同。

图所示,标记为1的粉色箭头再次表示应用程序将其数据提交给RAM和SLOG上的ZIL。SLOG对写入ZIL操作进行ACK(绿色箭头标记为2),然后ZFS将数据从RAM中刷新到磁盘(灰色箭头标记为3)。

异步写

异步写有一段“不稳定”的历史。您已经知道应该避免异步写操作,如果决定采用异步写操作,则应该准备好在出现故障时处理损坏的数据。对于大多数文件系统,这是一个好的建议。然而,用ZFS就没有什么好害怕的了。由于ZFS的体系结构设计,所有数据都被提交到事务组中的磁盘。此外,事务是原子的,这意味着您可以获得所有事务,也可以不获得任何事务。你永远不会得到部分写入。异步写入也是如此。因此,您的数据在磁盘上总是一致的——即使是异步写入。

如果是这样,那异步写流程是什么样的?当你在你的数据集上启用“sync=disabled”时,实际上会在RAM中驻留一个ZIL。按照之前同步架构的标准,应用程序的数据块被发送到位于RAM中的ZIL。一旦数据进入ZIL, RAM就会确认写入操作,然后按照同步数据的标准将数据刷新到磁盘。

我知道你在想什么:“等一下!异步写入不需要确认!”不总是正确的。对于ZFS,有一点是肯定的,它只是一个来自非常非常快和非常低潜在的易失性存储。ACK几乎是瞬时的。如果出现崩溃或其他一些导致RAM失去电源的故障,并且写没有保存到非易失性存储,那么写就会丢失。然而,这意味着您丢失了新数据,并且只能使用旧的但一致的数据。记住,使用ZFS时,数据是在原子事务中提交的。
(简单的说,在ZFS中即使发生故障,最多也就是丢掉最近5分钟的数据,所以数据是5分钟前的就数据,但是数据是一致的)。

下图展示了异步写操作。同样,粉色的1号箭头表示最初写入RAM中的ZIL的应用程序数据块。绿色的2号箭头表示RAM的ACK。然后,正如带数字3的灰色箭头所示,ZFS将数据刷新到磁盘,这与前面的每个实现相同。注意,在这个图中,即使你有一个SLOG,在异步写的时候,它将被绕过,没有使用。

免责声明

这是我和我的同事对ZIL的理解。这是在阅读大量文档、理解一些计算机科学理论和理解遵循ACID的RDBMS是如何工作的(它是以类似的方式构建的)之后完成的。如果你认为这是不正确的,请在评论中告诉我,我们可以讨论架构。

当然,我忽略了一些细节,比如在不再使用ZIL之前,它将保存多少数据、事务组写入的时间,以及其他事情。然而,还应该注意的是,除了一些晦涩的文档之外,似乎没有任何关于ZIL如何确切工作的可靠示例。所以,我想最好在这里说明一下,这样其他人就不会像我一样困惑了。对我来说,图总是能让事情更清晰地理解。

参考资料

https://pthree.org/2013/04/19/zfs-administration-appendix-a-visualizing-the-zfs-intent-log/

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