介绍 Solaris ZFS 文件系统,它在 Linux FUSE、原生内核模块和 Antergos Linux 安装程序中的实现。

自 2005 年 10 月出现以来,ZFS 仍然是最技术先进且功能完整的文件系统之一。Sun 原始的 Zettabyte 文件系统的代码已根据 CDDL 开源许可证发布,此后它已成为 FreeBSD 的标准组件,并缓慢迁移到各种 BSD 分支,同时保持对 OpenSolaris 后代(包括 OpenIndiana 和 SmartOS)的强大控制。

Oracle 是 ZFS 的所有者和管理者,并且在 Linux 文件系统方面处于特殊地位。Btrfs 是 ZFS 的主要竞争对手,它在 Oracle 开始开发,并且是 Oracle Linux 的核心组件,尽管存在稳定性问题,但红帽最近决定弃用 Btrfs 可能会为 Oracle 的 Linux 路线图带来兼容性和支持方面的挑战。Oracle 显然非常熟悉 Linux 文件系统领域,最近发布了 XFS 的“dedup”补丁。ZFS 是唯一稳定、保护您的数据、经证实能在最恶劣的环境中生存,并且具有长期使用历史以及广为人知的优缺点的文件系统选项。

由于 CDDL 与 Linux 的 GPL 许可证不兼容,ZFS (主要) 被排除在 Linux 之外。Linux 社区的明确希望是 Oracle 将以可以包含在 Linux 中的形式重新许可 ZFS,我们都应该温和地劝说 Oracle 这样做。显然,ZFS 的重新许可将对 Btrfs 和 Linux 的其余部分产生明显的影响,我们应该努力理解 Oracle 作为这些工具持有者的立场。然而,Oracle 继续捐赠大型软件项目以进行独立领导。Oracle 慷慨的例子包括 OpenOffice 和最近的 Java Enterprise Edition,因此 Oracle 的慷慨大方在某个时候也可能扩展到 ZFS 并非不可想象。

为了进一步推进这一对话,我想研究 Linux 的 ZFS 的各种版本。首先从以 RPM 为中心的环境开始,我首先描述如何安装最小侵入性的 FUSE 实现,然后继续从源代码进行 ZFS 模块的原生安装。最后,在抛开 RPM 之后,我继续介绍 Antergos 发行版,它实现了原生 ZFS 作为受支持的安装选项。

ZFS 技术背景

ZFS 与其他存储管理方法类似,但在某些方面,它又截然不同。ZFS 通常不使用 Linux 逻辑卷管理器 (LVM) 或磁盘分区,并且在为 zpool 准备介质之前删除分区和 LVM 结构通常很方便。

zpool 是 LVM 的类似物。一个 zpool 跨越一个或多个存储设备,并且 zpool 的成员可以是几种不同的类型。基本存储元素是单个设备、镜像和 raidz。所有这些存储元素都称为 vdev。

zpool 中的镜像 vdev 提供的存储空间大小与最小的物理驱动器相同。通过将更大的驱动器连接到镜像集并“重新银化”(同步镜像),然后从集合中分离较小的驱动器,可以升级(即增加大小)镜像 vdev。重新银化镜像将只涉及将已用块复制到目标设备—未使用的块不会被触及,这可以使重新银化比硬件维护的磁盘镜像(复制未使用存储)快得多。

ZFS 还可以维护 RAID 设备,与大多数存储控制器不同,它可以做到这一点而无需电池支持的缓存(只要物理驱动器遵守“写入屏障”)。ZFS 可以创建具有多级冗余的 raidz vdev,允许最多三个物理驱动器发生故障,同时保持阵列可用性。重新银化 raidz 也仅涉及已用块,并且可能比在 RAID 重建期间复制所有磁盘块的存储控制器快得多。raidz vdev 通常应包含 8-12 个驱动器(不建议使用更大的 raidz vdev)。请注意,raidz 中的驱动器数量无法扩展。

ZFS 非常倾向于管理裸磁盘。RAID 控制器应配置为呈现裸设备,而不是硬件 RAID 阵列。ZFS 能够比任何 RAID 控制器更好地强制执行存储完整性,因为它对文件系统的结构有深入的了解。所有控制器都应配置为呈现“Just a Bunch Of Disks”(JBOD),以便在 ZFS 中获得最佳结果。

数据安全是 ZFS 的一个重要设计特性。写入 zpool 的所有块都会被积极地进行校验和,以确保数据的一致性和正确性。您可以从 sha256、fletcher2 或 fletcher4 中选择校验和算法。您还可以禁用用户数据上的校验和,但强烈不建议这样做(此设置可能在速度至关重要,而一致性和恢复无关紧要的 scratch/tmp 文件系统上很有用;但是,对于 ZFS 中的临时文件系统,建议使用 sync=disabled 设置。

您可以随时更改校验和算法,新块将使用更新后的算法。校验和与数据块分开存储,与父块一起存储,希望可以检测到局部块损坏。如果发现某个块与父块的校验和不一致,则会从镜像或 raidz 设备检索该块的备用副本,重写到坏块上,然后完成 I/O 而不会发生意外。ZFS 文件系统可以使用这些技术来“自我修复”,并保护自己免受硬盘盘片上“位衰减”数据更改的影响,这些更改是由控制器错误、读/写头的电源丢失/波动,甚至宇宙射线的轰击引起的。

ZFS 可以通过维护块校验和及其位置的可搜索索引来实现“重复数据删除”。如果要写入的新块与索引中的现有块匹配,则会使用现有块,并节省空间。这样,多个文件可以通过维护公共块的单个副本共享内容,如果它们的任何内容发生更改,它们将从该副本中分离出来。文档指出,在启用重复数据删除之前,必须设置“支持重复数据删除的校验和”,并以 sha256 为例—校验和必须是“抗冲突的”,以便唯一地标识一个块,以确保重复数据删除的安全性。请注意,启用重复数据删除后,ZFS 的内存需求会急剧增加,这可能会迅速压垮资源不足的系统。

zpool 可以容纳数据集、快照、克隆和卷。“数据集”是具有挂载点且可以修改的标准 ZFS 文件系统。“快照”是文件系统的某个时间点的副本,并且随着父数据集的更改,快照将收集原始块以维护一致的过去映像。“克隆”可以基于快照构建,并允许将一组不同的更改应用于过去的映像,从而有效地允许文件系统分支—克隆和原始数据集将继续共享未更改的块,但在其他方面会发生分歧。“卷”类似于块设备,可以使用任何类型的文件系统进行环回挂载,或者可以作为 iscsi 目标呈现。校验和在卷上强制执行。请注意,与分区或逻辑卷不同,zpool 中的元素可以混合在一起。ZFS 知道磁盘的外边缘比内部快,它可能会决定在这些位置混合来自 zpool 中多个对象的块以提高性能。由于文件系统的这种混合,对 zpool 的取证分析既困难又昂贵

但是,无论您搜索多少,都没有 ZFS 恢复工具。欢迎您致电 Ontrack 等公司进行数据恢复。我认识一个人这样做过,他们花了 3000 美元只是为了弄清楚他们的数据是否可以恢复。然后他们又花了 15000 美元才找回了 200GB 的数据。

ZFS 数据集没有 fsck 或碎片整理工具。启动过程永远不会因为数据集未干净卸载而延迟。有一个“scrub”工具可以遍历数据集并验证所有 vdev 上每个已用块的校验和,但 scrub 在已挂载和活动的数据集上进行。ZFS 可以很好地从断电或其他脏卸载中恢复。

ZFS 中的碎片是一个更大的问题,它似乎更多地与剩余存储容量有关,而不是快速的文件增长和减少。当一个重度使用的数据集达到 50% 满时,其性能将开始下降,当 ZFS 开始使用“最佳拟合”而不是“首次拟合”来存储新块时,其性能将急剧下降到 80% 以上的使用率。在使用率降至 50% 以下后重新获得性能可能需要删除和重新银化包含 vdev 中的物理磁盘,直到数据集的所有块都已迁移。否则,应完全卸载并擦除数据集,然后重新加载内容,使其使用率不超过 50%(zfs send 和 receive 实用程序对此目的很有用)。重要的是为将要大量使用的数据集提供充足的可用磁盘空间。

强烈建议将 ECC 内存与 ZFS 一起使用。建议使用纠错内存,因为它对于正确处理维护 zpool 一致性的校验和至关重要。内存可能会因系统错误和宇宙射线而改变—ECC 内存可以纠正单位错误,并在检测到多位错误时使系统崩溃/停止运行。ECC 内存通常在服务器中找到,但在台式机和笔记本电脑中变得有些罕见。有人警告“死亡擦除”,并描述了来自非 ECC RAM 的实际数据丢失。但是,ZFS 的一位创建者表示,当使用非 ECC 内存时,所有文件系统都很脆弱,而 ZFS 实际上比大多数文件系统在故障中更优雅,并进一步描述了强制 ZFS 重复重新计算内存中校验和的未记录设置,这最大限度地减少了非 ECC RAM 的危险。一份冗长的配置指南使用这些未记录的设置解决了非 ECC 环境中 ZFS 的安全性 (https://www.csparks.com/ZFS%20Without%20Tears.html),但该指南似乎并未涵盖 FUSE 实现。

zfs-fuse

Linux 的 FUSE 实现于 2006 年收到了 ZFS 端口。FUSE 是一个接口,允许文件系统由在用户空间中运行的进程实现。Fedora 长期以来一直将 zfs-fuse 维护为 RPM 软件包,但此软件包未出现在任何基于 Red Hat 的发行版中,包括 Oracle Linux。红帽似乎有意省略了任何与 ZFS 支持相关的 RPM。

FUSE 实现可能是(目前)在 Linux 上以完全符合 CDDL 和 GPL 的方式使用 ZFS 的唯一方法。

与内核 ZFS 实现相比,FUSE 端口相对较慢。FUSE 通常不是以与 NFS 兼容的方式安装的,因此如果不准备具有 NFS 支持的 FUSE 版本(如果提供 fsid=,则 NFSv4 可能可用),则无法通过网络导出 zfs-fuse 文件系统。zfs-fuse 实现对于本地、存档和潜在的压缩数据集可能是合理的。有些人使用 Btrfs 进行临时压缩文件系统,而 zfs-fuse 当然是类似活动的选项。

可以在 Oracle Linux 7.4 中工作的 zfs-fuse 的最后一个版本是 Fedora 25 中的 RPM。Fedora 26 中有一个新的 ZFS 版本,但由于 OpenSSL 依赖关系,它无法安装在 Oracle Linux 7.4 上—红帽的 OpenSSL 现在太旧了。以下显示了安装 ZFS RPM


# rpm -Uvh zfs-fuse-0.7.0-23.fc24.x86_64.rpm
Preparing...                 ################################# [100%]
Updating / installing...
   1:zfs-fuse-0.7.0-23.fc24  ################################# [100%]

# cat /etc/redhat-release /etc/oracle-release
Red Hat Enterprise Linux Server release 7.4 (Maipo)
Oracle Linux Server release 7.4

必须先执行 zfs-fuse 用户空间代理,然后才能操作任何 zpool(请注意,为此目的包含了一个 systemd 单元)


# zfs-fuse
#

举一个简单的例子,让我们重新分配一个包含 Windows 7 安装的小型硬盘


# fdisk -l /dev/sdb

Disk /dev/sdb: 160.0 GB, 160000000000 bytes, 312500000 sectors
Disk label type: dos
Disk identifier: 0x8d206763

   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1   *        2048      206847      102400    7  HPFS/NTFS/exFAT
/dev/sdb2          206848   312496127   156144640    7  HPFS/NTFS/exFAT

将整个磁盘专用于 zpool 通常是最方便的,因此请删除所有现有分区


# fdisk /dev/sdb
Welcome to fdisk (util-linux 2.23.2).

Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): d
Partition number (1,2, default 2): 2
Partition 2 is deleted

Command (m for help): d
Selected partition 1
Partition 1 is deleted

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.

现在可以在驱动器上添加一个 zpool(请注意,创建池会添加一个同名的数据集,正如您在此处所见,该数据集会自动挂载)


# zpool create vault /dev/sdb

# df | awk 'NR==1||/vault/'
Filesystem          1K-blocks     Used Available Use% Mounted on
vault               153796557       21 153796536   1% /vault

# mount | grep vault
vault on /vault type fuse.zfs

在非冗余设备上创建 zpool 非正式地称为“讨厌你的数据”,并且应仅出于演示目的而考虑。但是,非冗余介质(例如,闪存驱动器)上的 zpool 相对于 VFAT 具有明显的数据一致性和压缩优势,并且可以为这样的数据集调整 copies 参数,以强制将所有块多次记录在介质上(最多三次)以提高可恢复性。

可以使用 zpool create vault mirror /dev/sdb /dev/sdc 创建镜像驱动器。可以使用 zpool attach 将其他驱动器作为镜像添加到现有驱动器。可以使用 zpool create vault raidz /dev/sdb /dev/sdc /dev/sdd 创建简单的 RAIDset。

标准的 umount 命令(通常)不应用于卸载 ZFS 数据集—请改用 zpool/zfs 工具(请注意是“unmount”而不是“umount”拼写)


# zfs unmount vault

# df | awk 'NR==1||/vault/'
Filesystem          1K-blocks     Used Available Use% Mounted on

# zfs mount vault

# df | awk 'NR==1||/vault/'
Filesystem          1K-blocks     Used Available Use% Mounted on
vault               153796557       21 153796536   1% /vault

可以通过更改“挂载点”将 ZFS 数据集挂载到新位置


# zfs unmount vault

# mkdir /root/vault

# zfs set mountpoint=/root/vault vault

# zfs mount vault

# df | awk 'NR==1||/vault/'
Filesystem          1K-blocks     Used Available Use% Mounted on
vault               153796547       21 153796526   1% /root/vault

# zfs unmount vault

# zfs set mountpoint=/vault vault

# zfs mount vault

# df | awk 'NR==1||/vault/'
Filesystem          1K-blocks     Used Available Use% Mounted on
vault               153796547       21 153796526   1% /vault

挂载点被保留,并在重启后仍然存在。

创建一个额外的数据集(并挂载它)就像创建一个目录一样简单(请注意,此命令可能需要一些时间)


# zfs create vault/tmpdir

# df | awk 'NR==1||/(vault|tmpdir)/'
Filesystem          1K-blocks     Used Available Use% Mounted on
vault               153796496      800 153795696   1% /vault
vault/tmpdir        153795717       21 153795696   1% /vault/tmpdir

# cp /etc/yum.conf /vault/tmpdir/

# ls -l /vault/tmpdir/
-rw-r--r--. 1 root root 813 Sep 23 16:47 yum.conf

ZFS 在数据集中支持多种类型的压缩。不同程度的 Gzip、zle 和 lzjb 都可以存在于单个挂载点中。校验和算法也可以动态调整


# zfs get compress vault/tmpdir
NAME          PROPERTY     VALUE     SOURCE
vault/tmpdir  compression  off       local

# zfs get checksum vault/tmpdir
NAME          PROPERTY  VALUE      SOURCE
vault/tmpdir  checksum  on         default

# zfs set compression=gzip vault/tmpdir

# zfs set checksum=fletcher2 vault/tmpdir

# cp /etc/redhat-release /vault/tmpdir

# zfs set compression=zle vault/tmpdir

# zfs set checksum=fletcher4 vault/tmpdir

# cp /etc/oracle-release /vault/tmpdir

# zfs set compression=lzjb vault/tmpdir

# zfs set checksum=sha256 vault/tmpdir

# cp /etc/os-release /vault/tmpdir

请注意,可以调整 GZIP 压缩因子(默认值为 6,就像 GNU GZIP 实用程序中一样)。这将直接影响数据集的速度和响应能力


# zfs set compression=gzip-1 vault/tmpdir

# cp /etc/profile /vault/tmpdir

# zfs set compression=gzip-9 vault/tmpdir

# cp /etc/grub2.cfg /vault/tmpdir

# ls -l /vault/tmpdir
-rw-r--r--. 1 root root 6308 Sep 23 17:06 grub2.cfg
-rw-r--r--. 1 root root   32 Sep 23 17:00 oracle-release
-rw-r--r--. 1 root root  398 Sep 23 17:00 os-release
-rw-r--r--. 1 root root 1795 Sep 23 17:05 profile
-rw-r--r--. 1 root root   52 Sep 23 16:59 redhat-release
-rw-r--r--. 1 root root  813 Sep 23 16:58 yum.conf

如果不再需要数据集,则可以将其删除


# zfs destroy vault/tmpdir

# df | awk 'NR==1||/(vault|tmpdir)/'
Filesystem          1K-blocks     Used Available Use% Mounted on
vault               153796523      800 153795723   1% /vault

您可以通过复制几个文件并创建快照来演示 ZFS 中的恢复


# cp /etc/passwd /etc/group /etc/shadow /vault

# ls -l /vault
-rw-r--r--. 1 root root  965 Sep 23 14:41 group
-rw-r--r--. 1 root root 2269 Sep 23 14:41 passwd
----------. 1 root root 1255 Sep 23 14:41 shadow

# zfs snapshot vault@goodver

# zfs list -t snapshot
NAME            USED  AVAIL  REFER  MOUNTPOINT
vault@goodver      0      -    27K  -

然后您可以模拟更多涉及关键文件丢失的文件操作


# rm /vault/shadow
rm: remove regular file '/vault/shadow'? y

# cp /etc/resolv.conf /etc/nsswitch.conf /etc/services /vault/

# ls -l /vault
-rw-r--r--. 1 root root    965 Sep 23 14:41 group
-rw-r--r--. 1 root root   1760 Sep 23 16:14 nsswitch.conf
-rw-r--r--. 1 root root   2269 Sep 23 14:41 passwd
-rw-r--r--. 1 root root     98 Sep 23 16:14 resolv.conf
-rw-r--r--. 1 root root 670311 Sep 23 16:14 services

通常,快照在数据集的 .zfs 目录中可见。但是,zfs-fuse 实现中不存在此功能,因此您被迫创建一个克隆来检索您丢失的文件


# zfs clone vault@goodver vault/history

# ls -l /vault/history
-rw-r--r--. 1 root root  965 Sep 23 14:41 group
-rw-r--r--. 1 root root 2269 Sep 23 14:41 passwd
----------. 1 root root 1255 Sep 23 14:41 shadow

请注意,克隆不是只读的,您可以修改它。两个挂载点将维护一组公共块,但在其他方面是独立的


# cp /etc/fstab /vault/history

# ls -l /vault/history
-rw-r--r--. 1 root root  541 Sep 23 16:23 fstab
-rw-r--r--. 1 root root  965 Sep 23 14:41 group
-rw-r--r--. 1 root root 2269 Sep 23 14:41 passwd
----------. 1 root root 1255 Sep 23 14:41 shadow

假设您已完成恢复活动,您可以销毁克隆和快照。此时对父数据集进行 scrub 以验证其完整性可能是明智之举,然后您可以列出您的 zpool 历史记录以查看您会话的证据


# zfs destroy vault/history

# zfs destroy vault@goodver

# zpool scrub vault

# zpool status vault
  pool: vault
 state: ONLINE
 scrub: scrub in progress for 0h1m, 30.93% done, 0h3m to go
config:

       NAME        STATE     READ WRITE CKSUM
       vault       ONLINE       0     0     0
         sdb       ONLINE       0     0     0

errors: No known data errors

# zpool history vault

对于我对 zfs-fuse 的最后总结,我将列出 zpool 和 zfs 的软件版本历史记录。注意:至关重要的是,您需要使用您希望使用的最低 ZFS 版本创建 zpool,在本例中,zpool 版本为 23,zfs 版本为 4


# zpool upgrade -v
This system is currently running ZFS pool version 23.

The following versions are supported:

VER  DESCRIPTION
---  --------------------------------------------------------
 1   Initial ZFS version
 2   Ditto blocks (replicated metadata)
 3   Hot spares and double parity RAID-Z
 4   zpool history
 5   Compression using the gzip algorithm
 6   bootfs pool property
 7   Separate intent log devices
 8   Delegated administration
 9   refquota and refreservation properties
 10  Cache devices
 11  Improved scrub performance
 12  Snapshot properties
 13  snapused property
 14  passthrough-x aclinherit
 15  user/group space accounting
 16  stmf property support
 17  Triple-parity RAID-Z
 18  Snapshot user holds
 19  Log device removal
 20  Compression using zle (zero-length encoding)
 21  Deduplication
 22  Received properties
 23  Slim ZIL


# zfs upgrade -v
The following filesystem versions are supported:

VER  DESCRIPTION
---  --------------------------------------------------------
 1   Initial ZFS filesystem version
 2   Enhanced directory entries
 3   Case insensitive and File system unique identifier (FUID)
 4   userquota, groupquota properties

原生 ZFS

您可以从 ZFS on Linux 站点获取 zfs.ko 内核模块并加载到 Linux 中,这将提供具有完整功能的高性能 ZFS。为了安装此软件包,您必须删除 FUSE 版本的 ZFS(假设它已按照上一节中的方式安装)。


# rpm -e zfs-fuse
Removing files since we removed the last package

删除 FUSE 后,您需要在目标系统上安装一个新的 yum 存储库。Red Hat 衍生版本上的 ZFS 可能需要网络访问 ZFS 存储库(独立安装将更加困难,此处不作介绍)。


# yum install \
   http://download.zfsonlinux.org/epel/zfs-release.el7_4.noarch.rpm
...
====================================================================
 Package                          Repository                   Size
====================================================================
Installing:
 zfs-release                      /zfs-release.el7_4.noarch   2.9 k

====================================================================
Install  1 Package

Total size: 2.9 k
Installed size: 2.9 k
Is this ok [y/d/N]: y
...

Installed:
  zfs-release.noarch 0:1-5.el7_4

Complete!

配置存储库后,加载 GPG 密钥。


# gpg --quiet --with-fingerprint /etc/pki/rpm-gpg/RPM-GPG-KEY-zfsonlinux
pub  2048R/F14AB620 2013-03-21 ZFS on Linux
 Key fingerprint = C93A FFFD 9F3F 7B03 C310  CEB6 A9D5 A1C0 F14A B620
sub  2048R/99685629 2013-03-21

此时,您已准备好继续进行原生 ZFS 安装。

此处使用的测试系统 Oracle Linux 7.4 通常可以从两个内核之一启动。有一个“Red Hat 兼容内核”和一个“Unbreakable Enterprise Kernel”(UEK)。虽然 FUSE 版本在两个内核下都完全正常运行,但原生 ZFS 安装程序不适用于 UEK(这意味着使用标准 ZFS 安装会排除 Oracle Ksplice)。如果您正在运行 Oracle Linux,则在操作原生 ZFS 配置时,您必须在 RHCK 上启动,这包括初始安装。在运行 UEK 时,请勿尝试安装或任何其他原生 ZFS 活动。


# rpm -qa | grep ^kernel | sort
kernel-3.10.0-693.2.2
kernel-devel-3.10.0-693.2.2
kernel-headers-3.10.0-693.2.2
kernel-tools-3.10.0-693.2.2
kernel-tools-libs-3.10.0-693.2.2
kernel-uek-4.1.12-103.3.8.1
kernel-uek-firmware-4.1.12-103.3.8.1

ZFS 安装实际上使用 yum 在默认配置 (DKMS) 中编译 C 源代码,然后使用 dracut 准备一个 initrd(在安装期间使用 top 监控此过程)。此安装将需要一些时间,并且有一些关于在备用安装配置 (kABI) 中使用预编译的 zfs.ko 集合的说明。此处使用的测试平台是 Oracle Linux,并且 Red Hat 兼容内核可能无法与预编译的 zfs.ko 集合完全互操作(在准备本文时未进行测试),因此保留了默认的 DKMS 构建。这是一个安装会话示例


# yum install kernel-devel zfs
...
====================================================================
 Package                                      Repository        Size
====================================================================
Installing:
 zfs                                                 zfs       405 k
Installing for dependencies:
 dkms                                                epel       78 k
 libnvpair1                                          zfs        29 k
 libuutil1                                           zfs        35 k
 libzfs2                                             zfs       129 k
 libzpool2                                           zfs       587 k
 spl                                                 zfs        29 k
 spl-dkms                                            zfs       454 k
 zfs-dkms                                            zfs       4.9 M

====================================================================
Install  1 Package (+8 Dependent packages)


Total download size: 6.6 M
Installed size: 29 M
Is this ok [y/d/N]: y
...
   - Installing to /lib/modules/3.10.0-693.2.2.el7.x86_64/extra/
spl:
splat.ko:
zavl:
znvpair.ko:
zunicode.ko:
zcommon.ko:
zfs.ko:
zpios.ko:
icp.ko:

Installed:
  zfs.x86_64 0:0.7.1-1.el7_4

Complete!

yum 会话结束后,您可以将原生 zfs.ko 加载到“RHCK”Linux 内核中,这将拉入许多依赖模块


# modprobe zfs

# lsmod | awk 'NR==1||/zfs/'
Module                  Size  Used by
zfs                  3517672  0
zunicode              331170  1 zfs
zavl                   15236  1 zfs
icp                   266091  1 zfs
zcommon                73440  1 zfs
znvpair                93227  2 zfs,zcommon
spl                   102592  4 icp,zfs,zcommon,znvpair

此时,可以将 FUSE 创建的池重新导入到系统中(请注意错误)


# /sbin/zpool import vault
cannot import 'vault': pool was previously in use from another system.
Last accessed at Sun Sep 24 2017
The pool can be imported, use 'zpool import -f' to import the pool.

# /sbin/zpool import vault -f

导入将自动挂载数据集。


# ls -l /vault
-rw-r--r--. 1 root root    965 Sep 23 14:41 group
-rw-r--r--. 1 root root   1760 Sep 23 16:14 nsswitch.conf
-rw-r--r--. 1 root root   2269 Sep 23 14:41 passwd
-rw-r--r--. 1 root root     98 Sep 23 16:14 resolv.conf
-rw-r--r--. 1 root root 670311 Sep 23 16:14 services

您可以创建一个快照,然后删除另一个关键文件


# /sbin/zfs snapshot vault@goodver

# rm /vault/group
rm: remove regular file '/vault/group'? y

此时,您可以在 /vault/.zfs 目录中搜索丢失的文件(请注意,.zfs 不会通过 ls -a 显示,但它仍然存在)。


# ls -la /vault
drwxr-xr-x.  2 root root      6 Sep 25 17:47 .
dr-xr-xr-x. 19 root root   4096 Sep 25 17:17 ..
-rw-r--r--.  1 root root   1760 Sep 23 16:14 nsswitch.conf
-rw-r--r--.  1 root root   2269 Sep 23 14:41 passwd
-rw-r--r--.  1 root root     98 Sep 23 16:14 resolv.conf
-rw-r--r--.  1 root root 670311 Sep 23 16:14 services

# ls -l /vault/.zfs
dr-xr-xr-x. 2 root root 2 Sep 23 13:54 shares
drwxrwxrwx. 2 root root 2 Sep 25 17:47 snapshot

# ls -l /vault/.zfs/snapshot/
drwxr-xr-x. 2 root root 7 Sep 24 18:58 goodver

# ls -l /vault/.zfs/snapshot/goodver
-rw-r--r--. 1 root root    965 Sep 23 14:41 group
-rw-r--r--. 1 root root   1760 Sep 23 16:14 nsswitch.conf
-rw-r--r--. 1 root root   2269 Sep 23 14:41 passwd
-rw-r--r--. 1 root root     98 Sep 23 16:14 resolv.conf
-rw-r--r--. 1 root root 670311 Sep 23 16:14 services

原生 ZFS 实现了更新的 zpool 和 zfs 软件版本—请记住,至关重要的是,您需要使用您将来打算使用的最低 ZFS 版本创建 zpool,在本例中,zpool 版本为 28,zfs 版本为 5。FUSE 版本在全新的 Red Hat 操作系统上安装以进行恢复要简单得多,因此在升级到原生 ZFS 版本之前请仔细考虑。


# /sbin/zpool upgrade -v
...

 23  Slim ZIL
 24  System attributes
 25  Improved scrub stats
 26  Improved snapshot deletion performance
 27  Improved snapshot creation performance
 28  Multiple vdev replacements


# /sbin/zfs upgrade -v
...

 4   userquota, groupquota properties
 5   System attributes

在 Red Hat 衍生版本上使用原生 ZFS 时,应伴有强烈的警告。

内核升级是一个令人担忧的问题。如果 zfs.ko 模块系列未正确安装,则无法将任何池联机。因此,在安装升级后的内核时,保留已知可工作的内核更为重要。正如我之前提到的,当使用默认原生安装时,Oracle 的 UEK 不支持 ZFS。

操作系统版本升级也引入了更严格的警告。在尝试升级之前,请删除所有 ZFS 软件。升级完成后,使用特定于新操作系统版本的 yum 存储库重复 ZFS 软件安装。ZFS on Linux 站点目前列出了 Red Hat 版本 6、7.3 和 7.4 的存储库。明智的做法是及时了解补丁和版本,并强烈考虑升级 7.0 – 7.2 Red Hat 衍生版本,其中考虑或需要原生 ZFS 安装。

另请注意,Solaris ZFS 具有加密和 Windows SMB 功能—这些功能在 Linux 端口中不起作用。

也许有一天,Oracle 会通过放宽许可条款来允许 Red Hat 系列捆绑原生 ZFS。那将是非常美好的一天。

Antergos

ZFS 仍然存在明显的法律模糊性。尽管 Ubuntu 最近宣布在其容器子系统中支持 zfs.ko 模块,但其 法律分析仍然模糊不清。毫不奇怪,没有一家主要的 Enterprise Linux 发行版愿意将 ZFS 作为一流的受支持文件系统捆绑在一起。

Antergos,Arch Linux 的后代,应运而生。Antergos 安装程序将以下载 ZFS 源代码并以类似于上一节的方式将其编译到安装内核中。尽管此处详述的示例安装并非一帆风顺,但它确实为运行与原生 RPM 安装相同版本发布的根文件系统留下了一个可工作、镜像的 zpool。

Antergos 没有做的是将 Linux 内核本身安装到两个驱动器。由于 Grub2 不支持 ZFS,并且似乎目前缺乏从 ZFS 数据集启动 Linux 的替代方案,因此仅在一个驱动器上为 /boot 配置了一个单独的 ext4 分区。我曾期望看到类似于 HP-UX 的 MirrorDisk/UX 的安装,其中固件配置了主引导路径和备用引导路径,并且操作系统足够智能,可以管理多个驱动器上引导文件系统和根文件系统的相同副本。我实际发现的是由 ZFS 镜像的根文件系统,但 /boot 中的内核不是,如果单个 ext4 /boot 分区失败,系统也无法启动。容错的 Antergos 安装将需要 RAID 硬件—ZFS 是不够的。

您可以使用以下命令下载 Antergos Live ISO 并将其作为可引导映像写入闪存驱动器:


# dd bs=4M if=antergos-17.9-x86_64.iso of=/dev/sdc

请注意,Antergos Minimal ISO 不支持 ZFS;它仅在 Live ISO 中。安装程序运行时需要 Internet 访问。最新的软件包将在安装程序会话中下载,并且很少从 ISO 介质中提取内容。

在 live ISO 上启动系统后,确保您已连接到互联网并激活安装程序对话框。请注意 beta 软件状态的警告—这指的是 ZFS、Btrfs 还是其他 Linux RAID 配置是一个悬而未决的问题。

图 1. 安装程序警告

选择您的区域或语言环境、时区、键盘布局(我建议选择“euro on 5”),然后选择您的桌面环境。在我选择 GNOME 后,我还添加了 Firefox 和 SSH 服务。最后,出现了一个 ZFS 选项—启用它(图 2)。

图 2. 切换 ZFS

如图 3 所示,我在 zpool 镜像中配置了两个 SATA 驱动器。我将池命名为“root”,这可能在首次启动时导致错误。另请注意 4k 块大小切换—这是一个与性能相关的设置,对于某些配置和使用模式可能建议使用。

图 3. 配置 zpool

下一页会提示您进行最终确认,然后擦除选定的驱动器,之后系统会提示您创建默认用户。

在安装程序运行时,您可以检查 zpool。打开终端并运行 sudo sh 后,我找到了以下有关 ZFS 配置的信息:


sh-4.4# zpool history
History for 'root': 2017-09-30 16:10:28
zpool create -f -m /install root mirror /dev/sda2 /dev/sdb
zpool set bootfs=root root
zpool set cachefile=/etc/zfs/zpool.cache root
zfs create -V 2G root/swap
zfs set com.sun:auto-snapshot=false root/swap
zfs set sync=always root/swap
zpool export -f root
zpool import -f -d /dev/disk/by-id -R /install 13754361671922204858

请注意,/dev/sda2 已镜像到 /dev/sdb,这表明 Antergos 已在 MBR 分区上安装了 zpool。更重要的是,这些驱动器的配置并不相同。这不是一个真正的冗余镜像,无法从任一驱动器启动。

在获取并安装安装包后,Antergos 将构建 zfs.ko。如果您在终端窗口中运行 top 命令,则可以看到对 gcc 的调用。

图 4. 构建 ZFS

我的安装会话正常完成,系统重新启动。GRUB 向我显示了 Antergos 启动画面,但在启动后,我被抛入了单用户模式


starting version 234
ERROR: resume: no device specified for hibernation
ZFS: Unable to import pool root.
cannot import 'root': pool was previously in use from another system.
Last accessed by <unknown> (hostid=0) at Tue Oct  3 00:06:34 2017
The pool can be imported, use 'zpool import -f' to import the pool.
ERROR: Failed to mount the real root device.
Bailing out, you are on your own. Good luck.

sh: can't access tty; job control turned off

[rootfs ]# zpool import -f root
cannot mount '/': directory is not empty
[rootfs ]# zfs create root/hold
[rootfs ]# cat /dev/vcs > /hold/vcs.txt

当原生驱动程序导入 FUSE 池时,也遇到了上面的 zpool 导入错误。我运行了强制导入 (zpool import -f root),该操作成功,然后创建了一个新的数据集并将终端复制到其中,因此您可以在此处查看会话。在 Ctrl-Alt-Delete 后,系统正常启动。在安装程序中将 zpool 命名为“root”可能导致了此问题。

我的测试系统没有 ECC 内存,所以我尝试调整下面的未记录内核参数,然后重新启动


echo options zfs zfs_flags=0x10 >> /etc/modprobe.d/zfs.conf

测试系统启动后,我检查了标志,发现 ECC 内存功能尚未设置。我手动设置了它,然后运行了 scrub


# cat /sys/module/zfs/parameters/zfs_flags
0

# echo 0x10 > /sys/module/zfs/parameters/zfs_flags

# cat /sys/module/zfs/parameters/zfs_flags
16

# zpool scrub root

# zpool status root
  pool: root
 state: ONLINE
  scan: scrub in progress since Sun Oct  1 12:08:50 2017
        251M scanned out of 5.19G at 25.1M/s, 0h3m to go
        0B repaired, 4.72% done
config:

        NAME                              STATE     READ WRITE CKSUM
        root                              ONLINE       0     0     0
          mirror-0                        ONLINE       0     0     0
            wwn-0x5000cca20cda462e-part2  ONLINE       0     0     0
            wwn-0x5000c5001a0d9823        ONLINE       0     0     0

errors: No known data errors

我还发现内核和 initrd 不在其文件名中包含版本号,这表明升级可能会覆盖它们。将它们复制到 boot 中的备用位置以确保备用内核可用可能是明智之举(这需要在 GRUB 中添加额外的菜单项)。


# ls -l /boot
-rw-r--r-- 1 root root 26729353 Sep 30 17:25 initramfs-linux-fallback.img
-rw-r--r-- 1 root root  9225042 Sep 30 17:24 initramfs-linux.img
-rw-r--r-- 1 root root  5474064 Sep 21 13:34 vmlinuz-linux

您可以通过使用 fdisk 探测驱动器来继续调查 Antergos zpool 镜像。


sh-4.4# fdisk -l /dev/sda
Disk /dev/sda: 232.9 GiB, 250059350016 bytes, 488397168 sectors
Disklabel type: dos

Device     Boot   Start       End   Sectors   Size Id Type
/dev/sda1  *       2048   1048575   1046528   511M 83 Linux
/dev/sda2       1048576 488397167 487348592 232.4G 83 Linux


sh-4.4# fdisk -l /dev/sdb
Disk /dev/sdb: 149 GiB, 160000000000 bytes, 312500000 sectors
Disklabel type: gpt

Device         Start       End   Sectors  Size Type
/dev/sdb1       2048 312481791 312479744  149G Solaris /usr & Apple ZFS
/dev/sdb9  312481792 312498175     16384    8M Solaris reserved 1

Antergos 似乎在随意处理分区类型。您还可以看到 /boot 分区是一个非冗余的 ext4。


# grep -v ^# /etc/fstab
UUID=f9fc... /boot ext4 defaults,relatime,data=ordered 0 0
/dev/zvol/root/swap swap swap defaults 0 0

# df|awk 'NR==1||/boot/'
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/sda1         498514   70732    418454  15% /boot

Antergos 没有配置完全容错的驱动器镜像,这是一个 已知问题。保存内核的 ext4 分区是单点故障,显然是 GRUB 所必需的。如果 /boot 丢失,则可以使用 Live ISO 访问 zpool,但恢复完整的系统可用性将需要付出更多努力。这可能也适用于 raidz。

结论

ZFS 是“经常被模仿,从未被超越”的文件系统。

ZFS 功能的主要竞争者似乎是 Btrfs、Apple APFS 和 Microsoft 的 ReFS。经过多年的 Btrfs 开发,它仍然 缺乏性能和成熟度(“我们仍然拒绝支持‘自动碎片整理’、‘带内重复数据删除’和更高级别的 RAID,因为这些选项的质量尚未达到应有的水平”)。苹果 几乎将 ZFS 捆绑到 OS X 中,但退出了并转而生产 APFS。微软也在尝试创建一个名为 ReFS 的下一代文件系统,但这样做再次证明了 Henry Spencer 的名言:“那些不理解 Unix 的人注定要拙劣地重新发明它。” ReFS 将缺乏压缩、重复数据删除和写入时复制快照。

我们所有人都有不希望丢失的关键数据。ZFS 是唯一稳定、保护我们数据、经证实能在最恶劣的环境中生存,并且具有长期使用历史以及广为人知的优缺点的文件系统选项。尽管许多需要其功能的 Linux 管理员可能会加载 ZFS,但安装和维护工具存在明显的缺点,可能会让粗心大意的人陷入困境。

现在是再次依靠 Oracle 的慷慨,并要求他们为社区的利益将 ZFS 文件系统完全开放给 Linux 的时候了。这将解决许多问题,包括 Oracle 的问题,并且将在 Linux 社区中产生善意,至少从文件系统的角度来看,这种善意非常缺乏。

免责声明

本文表达的观点和意见是作者的观点和意见,不一定反映 Linux Journal 的观点和意见。

Charles Fisher 拥有爱荷华大学的电气工程学位,并在一家财富 500 强矿业和制造公司担任系统和数据库管理员。

加载 Disqus 评论