第十章:杂项

本章涵盖了其他地方不太适合的小主题。

分离镜像

将存储组合到池中是ZFS的核心功能之一。但ZFS也允许进行反向操作——将镜像池拆分为多个相同的池。

以下示例演示向镜像池中添加磁盘,然后将池拆分为多个副本。

建议在每个镜像VDEV中始终至少维持两个提供者。

制作更深的镜像

镜像的深度描述了镜像包含的数据副本数量。

以下池是一个典型的条带镜像,包含两个镜像,每个镜像有两个磁盘:

我们可以为每个VDEV添加一个额外的磁盘,使池变得更深。

使用zpool attach命令,加上池名称、目标VDEV中已有的设备和新的设备:

在运行这两个命令之间,池的两个镜像中,一个镜像有三个设备、另一个镜像有两个设备。

最后,镜像看起来是这样的:

当池完成数据同步后就可以分离池了。

分离池

使用zpool split命令从每个VDEV中提取设备一创建新池。

该命令需要两个必需参数:要拆分的池名称和新创建的池的名称。以下示例将db池拆出一个db2池,这两个池完全相同:

ZFS删除最近添加到每个镜像中的设备以创建新池。拆分池不会自动导入新池。导入后,分割池看起来像这样:

这个池包含两个条带化的磁盘。

在原始池中,条带化的一对三向镜像已经变成了条带化的一对双磁盘镜像。

如果要持续使用这个分离出来的池,应添加更多的磁盘以创建适当的镜像。如果分离出来的池仅仅是为了提取备份,则可能不需要添加另一组磁盘。

SnapSpec

快照很棒,但它们像可能会肆意增长。一旦你习惯了使用快照来处理系统管理问题,你会发现自己因为拥有所有快照而面临磁盘空间短缺的问题。

删除单个快照很容易:

但按此方法销毁多个快照会及其繁琐。

可以使用snapspec识别多个相邻快照。虽然无法使用snapspec指定多个不同的快照,但可以按照一定的规律进行操作。

无论如何使用snapspec,都建议首先使用-n和-v运行命令。-v会显示运行命令的详细信息;-n则虚拟运行该命令。结合起来会在不影响实际数据的情况下观察可能出现的结果。

快照范围

最基本的snapspec是 fromsnap%tosnap。它会销毁所指示的两个对象之间的每个快照,包括它们自己:

如果@one和@three之间还有其他快照,比如@beforeupgrade,你会看到提示。这就是用-n的原因。

按年龄指定

可以使用@%foo销毁@foo和比它更老的快照,使用@foo%销毁@foo和比它更新的快照。

这比重新输入每个快照名称要容易得多。

快照屠宰

有时,你希望销毁所有快照。可使用@%:

现在,你可以重新开始累积快照了。

如果你拍摄了递归拍照,你可能像销毁整个快照树。添加-R选项以从数据集及其子数据集中删除快照。例如,我们完成了升级,并对结果感到满意,可以销毁所有以前的快照:

但是,建议把备份多保留一段时间。

恢复销毁的池

人生的高光时刻:等等,那个命令是一个可怕的错误。

你意识到了错误,但你那该死的右手小指已经按下了回车键。

一个可能发生的情况是销毁ZFS池。ZFS的设计者非常清楚这种综合症。

zpool destroy命令实际上不会损坏底层磁盘上的任何数据。相反,它将池标记为已被销毁。

zpool list命令会跳过标记为已销毁的池。如果尚未写入或物理移除已销毁的池的底层磁盘,那就可以恢复池。

使用zpool import -D命令可以查看已销毁的池:

你可能收到两种响应,分别对应可恢复池和不可恢复池。

可恢复池

下面这个池可以很容易恢复:

这个被销毁的池db2看起来像一个正常、健康的池。state行显示它是DESTROYED,但是输出信息显示了池中单个VDEV中的两个提供者,并且它们都在线。

要导入已销毁的池,可以在以上命令后面加上池名称:

不可恢复池

另一些销毁的池看起来像这样:

此例中state行显示为UNAVAIL,这意味着无法导入它。config中显示其中一个提供者也是UNAVAIL。ZFS找不到此池具有ZFS特定GUID的存储提供者。也许是你将该磁盘用在其他地方了,也许是把它从机箱拔出了。

这个例子中最令人烦恼的是什么?这个池是一个双盘镜像池。你有一份关于幸存提供者的数据的完美副本。但是池不完整,所以,无法导入它。根据action行的提示,需要找到那个丢失的盘,然后再试。

另一个常见的情况是,池中不再有SLOG设备。SLOG合适的硬件通常会直接在另一个池中重新使用或丢弃。使用zpool -m命令可以告诉zpool忽略丢失的SLOG并无论如何都导入池。

恢复时重命名池

有时,当你在恢复销毁的池时,你像重命名它。也许它与当前活动的池同名,也许这个池的功能已经更改。要在导入池时重命名它,请在池的旧名称后面添加新名称:

在其他方面,这与重命名导入的池相同。

克隆机器

ZFS对于虚拟机来说时一个非常明智的选择。虽然失去对磁盘的直接访问意味着ZFS无法处理错误检测,但快照和复制等功能使ZFS变得有价值。

大多数虚拟化系统都提供了克隆服务,有时伪装成你可以部署的标准模板。但是,如果将包含ZFS池的磁盘映像复制到新的虚拟机,则你的虚拟机是原始虚拟机的副本。这意味着一些应该是全局唯一的项目不再是。不在独立的虚拟机上。但是,如果要在虚拟机之间移动磁盘映像,则需要更改每个VM池的GUID。

guid属性包含池的guid。这里我们得到池db2的GUID:

要生成新的池GUID,请使用zpool reguid。将池名称作为参数:

现在,您可以将磁盘映像从一个虚拟机附加到另一个虚拟机器,而不会使ZFS变得非常适合。

如果由于某种原因zdb(8)找不到您的池,为池提供一个新的GUID也会有所帮助。

大小写不敏感文件系统

有些客户端(特别是OS X)希望文件系统不区分大小写。可以更改数据集的casesensitivity属性。此属性的默认值是sensitive(敏感),这是类Unix风格的区分大小写属性。将其改为mixed(混合),ZFS可以支持区分大小写和不区分大小写的请求。若改为insensitive,ZFS将完全不区分大小写。

只能在创建数据集时设定该属性:

要修改已有数据集的casesensitivity属性,就只能创建正确设置的属性创建新数据集,然后复制文件。

ZFS 深潜: zdb(8)

为了更好地了解ZFS内部发生的事情,能够窥探幕后是有帮助的。

检查ZFS的内部状态可以帮助你了解系统为什么以这种方式运行或表现。

FreeBSD中提供的ZFS工具套件包括zdb。

zdb手册页明确指出,此命令的输出通常反映了ZFS池的磁盘结构,并且本质上是不稳定的。大多数调用的精确输出没有记录,假设对ZFS内部有了解。“

输出基于磁盘上的内容和zdb对任何给定时刻内存中内容的模拟。

解释在很大程度上取决于操作员。

zdb命令有大量选项。所有这些都可以多次指定,每次都会增加信息的详细程度。

块统计

zdb实用程序可以检查块在池中的分配方式。我们将从虚拟机中检查一个非常小的池开始,然后检查越来越大的池。

使用-b选项和池名获取该池的块统计信息。

分析块统计信息需要大量内存,因为zdb在计算各种统计信息时必须跟踪每个块。一个非常大的池可能需要比主机更多的内存,最终内核的内存不足杀手会出于自卫而终止zdb。

在生产系统上运行此程序时要小心,因为zdb可能会使系统停止运行。

对于一个由三个8TB硬盘组成的RAID-Z1池,做一次zdb -b统计大概需要一个小时。

现在从虚拟机中的一个小型单磁盘池开始:

统计数据的第一部分涵盖了块指针,即包含元数据和数据块索引详细信息的块。

以下是一个来自只有一个磁盘VDEV的活动服务器的稍大的池:

这个池包含大量不可压缩的数据。bp physical条目显示,压缩系数为1.09。不过,再往下看分配的空间(bp allocated),实际上得到了0.98的压缩率。压缩几乎弥补了元数据造成的空间损失。

下面是一个来自四盘RAID-Z1的例子:

使用四盘RAID-Z1,你会损失25%的物理空间来实现奇偶检验。它有大约15GB的数据,但压缩会将其压缩到10GB。

不过看一下分配空间,压缩和RAID-Z元数据实际是相互抵消了。

下面是另一个四盘RAID-Z1,但数据更多:

它存储了大约845GB的数据,但由于是RAID-Z1,所以它实际分配了超过1TB的空间。

(对于我实际的NAS系统,有一个三盘RAID-Z1池。8T的数据,实际分配(bp allocated)了11T的空间,压缩比只有0.69。)

详细块统计

如果上面的数字不够详细,可以再加上第二个-b获得更详细的块统计数据:

你会得到一个统计表,包含以下列:

最后一行给出了总数。这个池有大约83K个指针块,代表2.01GB的数据。此数据使用856MB的逻辑空间,但由于ZFS添加了填充和元数据,则需要1.08GB。

下面看看Type列出现的这些类型:

ZFS 配置

使用zdb -C命令可以查看系统的ZFS配置。比如以下示例显示media池的配置信息:

这给出了media池的基本细节。其中一些信息相对明显,例如池的GUID和使用此池的主机的hostid。此池已提交15612202个事务组。vdev_children字段显示此池中有多少VDEV。

池VDEV信息以树状显示,列出每个VDEV,然后列出该VDEV中的磁盘。这是media池中的VDEV:

VDEV中的每个磁盘都有一个条目:

这告诉您关于ZFS GUID、FreeBSD设备节点和一些内部。

在最底部,您将看到此池上的只读功能列表:

如果使用第二个-C和池名,zdb将检索磁盘上的数据和缓存的数据,以便进行比较。这些应该有所不同吗?不是真的。

数据集信息

详细检查数据集还可以提供大量信息,并有助于可视化文件系统的内部。

数据集基本信息

使用zdb -d加上数据集名称,可以查看指定数据集的内部结构信息:

cr_txg字段显示了创建此数据集的事务组。它保存了3.82GB数据,其中有259339个对象。

对象包括目录和文件,还包括元数据、ACL和ZFS可以保存的所有其他类型的数据。

数据集细节

在以上命令上再加一个-d,可以得到更加详细的信息:

这个数据集中有一大堆文件、目录和相关内容。

系统管理员可能会对其中一些列感兴趣,第一列是编号、dblk列是用于此对象的记录大小、lsize是对象的逻辑大小(这是我们大多数人在说“文件大小”时想到的)。

第一行提供了基本信息。接下来会看到数据集中每个对象的详细信息。

虽然前几个对象总是ZFS元数据,但后面的对象大多数是文件和目录。

检查特定对象

数据集对象列表可能很有趣,但每个对象是什么?

通过在数据集名称后指定对象编号来检查对象。

我们从数据集的细节开始,比如创建txg和对象数量,就像我们在不太密集的zdb查询中看到的那样。我们还获得了更多的细节,比如当前的校验和以及其他只有在学习D&I时才有意义的东西。

然后我们得到一些关于文件本身的细节。

此文件的大小为4.50 KB,但数据大小(dsize)为8 KB,因为磁盘上的大小是整个扇区。 然后我们将进入文件的核心。

您将看到一堆传统的Unix信息:权限、文件名和路径、时间、父对象等。如果你用ls查看这个文件,它看起来是4139字节,但不包括任何支持它的ZFS元数据。

现在让我们考虑一个更大的lz4压缩文件。

这从基本的池信息开始,然后深入到文件本身。虽然此文件占用244 KB的磁盘空间,但其实际大小为896 KB。压缩减少了所需的磁盘空间量。

不过,在Unix信息之后,我们会得到一个间接块列表。

当文件大于recordsize(dblk)时,ZFS将其存储为多个单独的块。第一列是文件中的偏移量,以十六进制表示。十六进制中的数字20000是128KB。所讨论的文件有一个L1间接块,然后是七个实际保存数据的128KB L0块,最后一个实际上稍小。

检查特定文件

也许你想看看一个特定的文件——比如,看看它是用什么块大小写的。你不能轻易地从zdb–d中提取它,但你可以通过使用–i标志从ls(1)中获取序列号或索引节点号。在这里,出于某种难以形容的原因,我们对MySQL数据文件感兴趣。

这是zroot/var/mysql数据集上的文件132。

当使用inode编号工作时,用zdb -v查看此文件:

使用四个或更多-v选项显示传统的Unix信息和间接块。

Metaslabs 和自由空间直方图

每个顶级虚拟设备都被分解为metaslabs。ZFS在metaslab-by-metaslab基础上填充空间。

在ZFS分配空间时,它会寻找足够大的磁盘块来容纳新事务。当你的池满了,写入数据时唯一的选择就是把它分成剩下的小块空间。则就会造成ZFS性能随着池的填满而降低——可用空间变得碎片化。使用以下命令查看metaslab有多满:

每个metalab定义都以一个基本描述开始。这里我们看到VDEV 0,它有130个metalabs。然后我们继续对编号0的metalab进行处理。它就在池的开头,偏移量为0。该池有806个分配或分段,其中只有3%是可用的。

然后,就系统内存而言,我们得到了这个metalab中块分配的直方图:

第一列中的数字是块大小,以2的幂表示为千字节。213=8192,所以13是8KB。此元实验室有281个8KB的分配。

第14行是16KB。此元实验室有197个16KB的分配。

第15行是32KB,有189个分配,以此类推,一直到一个232(或4GB)的分配。

在内存中的metaslab直方图之后,我们可以看到磁盘上metaslab的版本是什么样子的。在繁忙的磁盘上,ZFS始终在分配和取消分配块。

向下滚动。不,更进一步。最终,您将看到一个看起来大不相同的后期元实验室。在这种情况下是Metaslab 43。

这个metalab有17893个分配,但46%是自由的。块大小分布也大不相同。

我们最常见的分配是17(128 KB)和20(1 MB)。

不过,这个磁盘暗示了为什么这个元实验室只有大约一半的空间。

注意碎片级别--11。在磁盘上,metaslab 43是碎片化的。这意味着许多自由空间块相对较小。通过旋转磁盘,连续存储文件块可以提高性能。如果ZFS需要编写一个大块,它可能会继续到稍后的metalab。

进一步深入你的metaslabs内部。

磁盘末尾附近的metalab由连续的128 GB块组成。如果这个池以前几乎满了,编号较高的元实验室可能会包含一些数据,而在这个池上,它们是不受影响的。

ZFS通常将VDEV划分为200个大小相等的metalab。您可以使用vfs.zfs.vdev.metalabs_per_vdev sysctl调整此数字,但必须在创建vdev之前设置sysctl。之所以选择数字200,是因为它似乎运行得很好,但metalab分配还有很大的实验空间。

当您通过用更大的磁盘替换VDEV来扩展VDEV时,ZFS会创建新的metalab来支持增加的空间。通过这种方式,你可以得到一个拥有200多个metalab的池。 ZFS一次只能在内存中保留这么多metalab。将VDEV扩展到其原始大小的许多倍可能会对性能产生负面影响,因为ZFS会在磁盘之间来回移动metalab。

Uberblock

如果不查看池的uberblock,这将是什么样的ZFS调试部分?

你能用这个做什么?不多。但在这一点上,ZFS几乎赤裸裸地躺在你面前。

你还能学到什么取决于你。