第 22 章。Z 文件系统 (ZFS)

ZFS 是一种高级文件系统,旨在解决以前存储子系统软件中发现的主要问题。

最初由 Sun™ 开发,正在进行的开源 ZFS 开发已移至 OpenZFS 项目

ZFS 有三个主要的设计目标

  • 数据完整性:所有数据都包含 校验和。ZFS 计算校验和并将其与数据一起写入。稍后读取该数据时,ZFS 会重新计算校验和。如果校验和不匹配,表示检测到一个或多个数据错误,ZFS 将尝试在有 ditto-、镜像- 或奇偶校验块的情况下自动更正错误。

  • 存储池:将物理存储设备添加到池中,并从该共享池中分配存储空间。所有文件系统和卷都可以使用该空间,并且可以通过将新的存储设备添加到池中来增加该空间。

  • 性能:缓存机制可提高性能。 ARC 是一种高级基于内存的读取缓存。ZFS 使用 L2ARC 提供第二级基于磁盘的读取缓存,并提供名为 ZIL 的基于磁盘的同步写入缓存。

完整的功能和术语列表见 ZFS 功能和术语

22.1. ZFS 的独特之处

ZFS 不仅仅是一个文件系统,它与传统文件系统有着根本的不同。将传统上分开的卷管理器和文件系统角色结合起来,为 ZFS 带来了独特的优势。文件系统现在了解磁盘的底层结构。传统文件系统只能一次存在于单个磁盘上。如果有两个磁盘,则需要创建两个独立的文件系统。传统的硬件 RAID 配置通过向操作系统呈现一个由物理磁盘提供的空间组成的单个逻辑磁盘来避免此问题,操作系统在此磁盘上放置一个文件系统。即使使用 GEOM 提供的软件 RAID 解决方案,位于 RAID 之上的 UFS 文件系统也认为它正在处理单个设备。ZFS 将卷管理器和文件系统结合起来,解决了这个问题,并允许创建共享可用存储池的所有文件系统。ZFS 了解物理磁盘布局的一个主要优势是,在向池中添加更多磁盘时,现有的文件系统会自动增长。然后,此新空间将变得对文件系统可用。ZFS 还可以对每个文件系统应用不同的属性。这使得创建独立的文件系统和数据集比创建单个整体文件系统更有用。

22.2. 快速入门指南

FreeBSD 可以在系统初始化期间挂载 ZFS 池和数据集。要启用它,请将以下行添加到 /etc/rc.conf

zfs_enable="YES"

然后启动服务

# service zfs start

本节中的示例假设三个 SCSI 磁盘,设备名为 da0da1da2。SATA 硬件用户应该使用 ada 设备名。

22.2.1. 单磁盘池

要使用单个磁盘设备创建一个简单的非冗余池,请使用

# zpool create example /dev/da0

要查看新池,请查看 df 的输出

# df
Filesystem  1K-blocks    Used    Avail Capacity  Mounted on
/dev/ad0s1a   2026030  235230  1628718    13%    /
devfs               1       1        0   100%    /dev
/dev/ad0s1d  54098308 1032846 48737598     2%    /usr
example      17547136       0 17547136     0%    /example

此输出显示了 example 池的创建和挂载,现在可以将其作为文件系统访问。为用户创建一些文件以浏览

# cd /example
# ls
# touch testfile
# ls -al
total 4
drwxr-xr-x   2 root  wheel    3 Aug 29 23:15 .
drwxr-xr-x  21 root  wheel  512 Aug 29 23:12 ..
-rw-r--r--   1 root  wheel    0 Aug 29 23:15 testfile

此池尚未使用任何高级 ZFS 功能和属性。要在该池上创建具有启用压缩的数据集,请使用

# zfs create example/compressed
# zfs set compression=gzip example/compressed

现在,example/compressed 数据集是一个 ZFS 压缩文件系统。尝试将一些大文件复制到 /example/compressed

使用以下命令禁用压缩

# zfs set compression=off example/compressed

要卸载文件系统,请使用 zfs umount,然后使用 df 进行验证

# zfs umount example/compressed
# df
Filesystem  1K-blocks    Used    Avail Capacity  Mounted on
/dev/ad0s1a   2026030  235232  1628716    13%    /
devfs               1       1        0   100%    /dev
/dev/ad0s1d  54098308 1032864 48737580     2%    /usr
example      17547008       0 17547008     0%    /example

要重新挂载文件系统以使其再次可访问,请使用 zfs mount 并使用 df 进行验证

# zfs mount example/compressed
# df
Filesystem         1K-blocks    Used    Avail Capacity  Mounted on
/dev/ad0s1a          2026030  235234  1628714    13%    /
devfs                      1       1        0   100%    /dev
/dev/ad0s1d         54098308 1032864 48737580     2%    /usr
example             17547008       0 17547008     0%    /example
example/compressed  17547008       0 17547008     0%    /example/compressed

运行 mount 会显示池和文件系统

# mount
/dev/ad0s1a on / (ufs, local)
devfs on /dev (devfs, local)
/dev/ad0s1d on /usr (ufs, local, soft-updates)
example on /example (zfs, local)
example/compressed on /example/compressed (zfs, local)

创建完 ZFS 数据集后,就像任何文件系统一样使用它。在需要时,在每个数据集的基础上设置其他可用功能。以下示例创建了一个名为 data 的新文件系统。假设该文件系统包含重要的文件,并将其配置为存储每个数据块的两个副本。

# zfs create example/data
# zfs set copies=2 example/data

使用 df 查看数据和空间使用情况

# df
Filesystem         1K-blocks    Used    Avail Capacity  Mounted on
/dev/ad0s1a          2026030  235234  1628714    13%    /
devfs                      1       1        0   100%    /dev
/dev/ad0s1d         54098308 1032864 48737580     2%    /usr
example             17547008       0 17547008     0%    /example
example/compressed  17547008       0 17547008     0%    /example/compressed
example/data        17547008       0 17547008     0%    /example/data

请注意,池中的所有文件系统都具有相同的可用空间。使用这些示例中的 df 显示了文件系统使用它们所需的存储空间,并且它们都从同一个池中获取存储空间。ZFS 消除了卷和分区等概念,并允许多个文件系统共享同一个池。

要销毁文件系统,然后销毁不再需要的池,请使用

# zfs destroy example/compressed
# zfs destroy example/data
# zpool destroy example

22.2.2. RAID-Z

磁盘会发生故障。避免磁盘故障导致数据丢失的一种方法是使用 RAID。ZFS 在其池设计中支持此功能。RAID-Z 池需要三个或更多磁盘,但提供的可用空间比镜像池多。

此示例创建一个 RAID-Z 池,并指定要添加到池中的磁盘

# zpool create storage raidz da0 da1 da2

Sun™ 建议在 RAID-Z 配置中使用的设备数量介于三个和九个之间。对于需要由 10 个或更多磁盘组成的单个池的环境,请考虑将其分解为更小的 RAID-Z 组。如果有两个磁盘可用,则 ZFS 镜像在需要时提供冗余。有关更多详细信息,请参阅 zpool(8)

前面的示例创建了 storage zpool。此示例在该池中创建一个名为 home 的新文件系统

# zfs create storage/home

启用压缩并存储目录和文件的额外副本

# zfs set copies=2 storage/home
# zfs set compression=gzip storage/home

要将其设为用户的新主目录,请将用户数据复制到该目录并创建相应的符号链接

# cp -rp /home/* /storage/home
# rm -rf /home /usr/home
# ln -s /storage/home /home
# ln -s /storage/home /usr/home

用户数据现在存储在新建的 /storage/home 中。通过添加新用户并以该用户身份登录来进行测试。

创建文件系统快照以便稍后回滚

# zfs snapshot storage/home@08-30-08

ZFS 创建的是数据集快照,而不是单个目录或文件的快照。

@ 字符是文件系统名称或卷名称之间的分隔符。在删除重要目录之前,请备份文件系统,然后回滚到目录仍然存在的早期快照

# zfs rollback storage/home@08-30-08

要列出所有可用的快照,请在文件系统的 .zfs/snapshot 目录中运行 ls。例如,要查看已拍摄的快照,请使用

# ls /storage/home/.zfs/snapshot

编写一个脚本来定期拍摄用户数据的快照。随着时间的推移,快照可能会占用大量磁盘空间。使用以下命令删除以前的快照

# zfs destroy storage/home@08-30-08

测试完成后,使用以下命令将 /storage/home 设为真正的 /home

# zfs set mountpoint=/home storage/home

运行 dfmount 以确认系统现在将该文件系统视为真正的 /home

# mount
/dev/ad0s1a on / (ufs, local)
devfs on /dev (devfs, local)
/dev/ad0s1d on /usr (ufs, local, soft-updates)
storage on /storage (zfs, local)
storage/home on /home (zfs, local)
# df
Filesystem   1K-blocks    Used    Avail Capacity  Mounted on
/dev/ad0s1a    2026030  235240  1628708    13%    /
devfs                1       1        0   100%    /dev
/dev/ad0s1d   54098308 1032826 48737618     2%    /usr
storage       26320512       0 26320512     0%    /storage
storage/home  26320512       0 26320512     0%    /home

这完成了 RAID-Z 配置。通过将以下行添加到 /etc/periodic.conf 中,将有关创建的文件系统的每日状态更新添加到夜间 periodic(8) 运行中

daily_status_zfs_enable="YES"

22.2.3. 恢复 RAID-Z

每个软件 RAID 都有一个方法来监控其 state。使用以下命令查看 RAID-Z 设备的状态

# zpool status -x

如果所有池都处于 在线 状态并且一切正常,则消息将显示为

all pools are healthy

如果存在问题,例如磁盘处于 离线 状态,则池状态将类似于

  pool: storage
 state: DEGRADED
status: One or more devices has been taken offline by the administrator.
	Sufficient replicas exist for the pool to continue functioning in a
	degraded state.
action: Online the device using 'zpool online' or replace the device with
	'zpool replace'.
 scrub: none requested
config:

	NAME        STATE     READ WRITE CKSUM
	storage     DEGRADED     0     0     0
	  raidz1    DEGRADED     0     0     0
	    da0     ONLINE       0     0     0
	    da1     OFFLINE      0     0     0
	    da2     ONLINE       0     0     0

errors: No known data errors

"OFFLINE" 显示管理员使用以下命令将 da1 设为离线

# zpool offline storage da1

现在关闭计算机并更换 da1。启动计算机并将 da1 返回到池中

# zpool replace storage da1

接下来,再次检查状态,这次不使用 -x 来显示所有池

# zpool status storage
 pool: storage
 state: ONLINE
 scrub: resilver completed with 0 errors on Sat Aug 30 19:44:11 2008
config:

	NAME        STATE     READ WRITE CKSUM
	storage     ONLINE       0     0     0
	  raidz1    ONLINE       0     0     0
	    da0     ONLINE       0     0     0
	    da1     ONLINE       0     0     0
	    da2     ONLINE       0     0     0

errors: No known data errors

在此示例中,一切正常。

22.2.4. 数据验证

ZFS 使用校验和来验证存储数据的完整性。创建文件系统会自动启用校验和。

可以禁用校验和,但不建议这样做!校验和占用很少的存储空间,并提供数据完整性。大多数 ZFS 功能在禁用校验和的情况下将无法正常工作。禁用这些校验和不会明显提高性能。

验证数据校验和(称为擦除)可确保 storage 池的完整性,方法是使用

# zpool scrub storage

擦除持续时间取决于存储的数据量。数据量越大,验证所需时间就越长。由于擦除是 I/O 密集型操作,因此 ZFS 允许一次运行一个擦除操作。擦除完成后,使用 zpool status 查看状态

# zpool status storage
 pool: storage
 state: ONLINE
 scrub: scrub completed with 0 errors on Sat Jan 26 19:57:37 2013
config:

	NAME        STATE     READ WRITE CKSUM
	storage     ONLINE       0     0     0
	  raidz1    ONLINE       0     0     0
	    da0     ONLINE       0     0     0
	    da1     ONLINE       0     0     0
	    da2     ONLINE       0     0     0

errors: No known data errors

显示上次擦除的完成日期有助于决定何时启动下一次擦除。定期擦除有助于保护数据免受静默损坏并确保池的完整性。

有关其他 ZFS 选项,请参阅 zfs(8)zpool(8)

22.3. zpool 管理

ZFS 管理使用两个主要实用程序。zpool 实用程序控制池的操作,并允许添加、删除、替换和管理磁盘。 zfs 实用程序允许创建、销毁和管理数据集,包括 文件系统

22.3.1. 创建和销毁存储池

创建 ZFS 存储池需要做出永久性决定,因为池结构在创建后无法更改。最重要的决定是将物理磁盘分组为哪种类型的 vdev。有关可能选项的详细信息,请参阅 vdev 类型 列表。创建池后,大多数 vdev 类型不允许向 vdev 中添加磁盘。例外情况是镜像,它允许向 vdev 中添加新磁盘,以及条带,它通过向 vdev 中附加新磁盘来升级为镜像。虽然添加新的 vdev 会扩展池,但池布局在池创建后无法更改。相反,请备份数据、销毁池并重新创建它。

创建一个简单的镜像池

# zpool create mypool mirror /dev/ada1 /dev/ada2
# zpool status
  pool: mypool
 state: ONLINE
  scan: none requested
config:

        NAME        STATE     READ WRITE CKSUM
        mypool      ONLINE       0     0     0
          mirror-0  ONLINE       0     0     0
            ada1    ONLINE       0     0     0
            ada2    ONLINE       0     0     0

errors: No known data errors

要使用单个命令创建多个 vdev,请指定由 vdev 类型关键字(在本例中为 mirror)分隔的磁盘组

# zpool create mypool mirror /dev/ada1 /dev/ada2 mirror /dev/ada3 /dev/ada4
# zpool status
  pool: mypool
 state: ONLINE
  scan: none requested
config:

        NAME        STATE     READ WRITE CKSUM
        mypool      ONLINE       0     0     0
          mirror-0  ONLINE       0     0     0
            ada1    ONLINE       0     0     0
            ada2    ONLINE       0     0     0
          mirror-1  ONLINE       0     0     0
            ada3    ONLINE       0     0     0
            ada4    ONLINE       0     0     0

errors: No known data errors

池也可以使用分区而不是整个磁盘。将 ZFS 放置在单独的分区中允许同一磁盘具有其他分区以用于其他目的。特别是,它允许添加具有引导代码和用于引导的文件系统分区。这允许从也是池成员的磁盘引导。在 FreeBSD 上,使用分区而不是整个磁盘不会对 ZFS 造成性能损失。使用分区还允许管理员对磁盘进行容量不足分配,使用少于磁盘的全部容量。如果相同标称大小的将来更换磁盘的实际容量略小,则较小的分区仍将适合,可以使用更换磁盘。

使用分区创建 RAID-Z2

# zpool create mypool raidz2 /dev/ada0p3 /dev/ada1p3 /dev/ada2p3 /dev/ada3p3 /dev/ada4p3 /dev/ada5p3
# zpool status
  pool: mypool
 state: ONLINE
  scan: none requested
config:

        NAME        STATE     READ WRITE CKSUM
        mypool      ONLINE       0     0     0
          raidz2-0  ONLINE       0     0     0
            ada0p3  ONLINE       0     0     0
            ada1p3  ONLINE       0     0     0
            ada2p3  ONLINE       0     0     0
            ada3p3  ONLINE       0     0     0
            ada4p3  ONLINE       0     0     0
            ada5p3  ONLINE       0     0     0

errors: No known data errors

销毁不再需要的池,以重新使用磁盘。销毁池需要先卸载该池中的文件系统。如果任何数据集正在使用,则卸载操作将失败而不会销毁池。使用 -f 强制销毁池。这可能会导致在那些数据集中有打开文件的应用程序中出现未定义的行为。

22.3.2. 添加和删除设备

有两种方法可以将磁盘添加到池中:使用 zpool attach 将磁盘附加到现有 vdev,或者使用 zpool add 将 vdev 添加到池中。一些 vdev 类型 允许在创建后将磁盘添加到 vdev 中。

使用单个磁盘创建的池缺乏冗余。它可以检测到损坏,但无法修复它,因为没有数据的其他副本。 copies 属性可能能够从诸如坏扇区之类的微小故障中恢复,但无法提供与镜像或 RAID-Z 相同级别的保护。从包含单个磁盘 vdev 的池开始,使用 zpool attach 将新磁盘添加到 vdev,创建一个镜像。还可以使用 zpool attach 将新磁盘添加到镜像组,从而提高冗余性和读取性能。对用于池的磁盘进行分区时,将第一个磁盘的布局复制到第二个磁盘。使用 gpart backupgpart restore 可以使此过程更轻松。

将单个磁盘(条带)vdev ada0p3 升级为镜像,方法是附加 ada1p3

# zpool status
  pool: mypool
 state: ONLINE
  scan: none requested
config:

        NAME        STATE     READ WRITE CKSUM
        mypool      ONLINE       0     0     0
          ada0p3    ONLINE       0     0     0

errors: No known data errors
# zpool attach mypool ada0p3 ada1p3
Make sure to wait until resilvering finishes before rebooting.

If you boot from pool 'mypool', you may need to update boot code on newly attached disk _ada1p3_.

Assuming you use GPT partitioning and _da0_ is your new boot disk you may use the following command:

        gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 da0
# gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ada1
bootcode written to ada1
# zpool status
  pool: mypool
 state: ONLINE
status: One or more devices is currently being resilvered.  The pool will
        continue to function, possibly in a degraded state.
action: Wait for the resilver to complete.
  scan: resilver in progress since Fri May 30 08:19:19 2014
        527M scanned out of 781M at 47.9M/s, 0h0m to go
        527M resilvered, 67.53% done
config:

        NAME        STATE     READ WRITE CKSUM
        mypool      ONLINE       0     0     0
          mirror-0  ONLINE       0     0     0
            ada0p3  ONLINE       0     0     0
            ada1p3  ONLINE       0     0     0  (resilvering)

errors: No known data errors
# zpool status
  pool: mypool
 state: ONLINE
  scan: resilvered 781M in 0h0m with 0 errors on Fri May 30 08:15:58 2014
config:

        NAME        STATE     READ WRITE CKSUM
        mypool      ONLINE       0     0     0
          mirror-0  ONLINE       0     0     0
            ada0p3  ONLINE       0     0     0
            ada1p3  ONLINE       0     0     0

errors: No known data errors

当无法将磁盘添加到现有 vdev 中时,例如对于 RAID-Z,另一种方法是将另一个 vdev 添加到池中。添加 vdev 可以通过将写入分散到各个 vdev 来提高性能。每个 vdev 都提供自己的冗余。混合使用 vdev 类型(如 mirrorRAID-Z)是可能的,但不建议这样做。将非冗余 vdev 添加到包含镜像或 RAID-Z vdev 的池,会使整个池中的数据面临风险。分散写入意味着非冗余磁盘的故障会导致写入池的每个块的一部分丢失。

ZFS 在每个 vdev 中对数据进行条带化。例如,对于两个镜像 vdev,这实际上是 RAID 10,它将写入条带化到两组镜像中。ZFS 分配空间,以便每个 vdev 在同一时间达到 100% 满。具有不同数量的可用空间的 vdev 会降低性能,因为更多的数据写入会转到可用空间更少的 vdev。

将新设备附加到引导池时,请记住更新引导代码。

将第二个镜像组(ada2p3ada3p3)附加到现有镜像

# zpool status
  pool: mypool
 state: ONLINE
  scan: resilvered 781M in 0h0m with 0 errors on Fri May 30 08:19:35 2014
config:

        NAME        STATE     READ WRITE CKSUM
        mypool      ONLINE       0     0     0
          mirror-0  ONLINE       0     0     0
            ada0p3  ONLINE       0     0     0
            ada1p3  ONLINE       0     0     0

errors: No known data errors
# zpool add mypool mirror ada2p3 ada3p3
# gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ada2
bootcode written to ada2
# gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ada3
bootcode written to ada3
# zpool status
  pool: mypool
 state: ONLINE
  scan: scrub repaired 0 in 0h0m with 0 errors on Fri May 30 08:29:51 2014
config:

        NAME        STATE     READ WRITE CKSUM
        mypool      ONLINE       0     0     0
          mirror-0  ONLINE       0     0     0
            ada0p3  ONLINE       0     0     0
            ada1p3  ONLINE       0     0     0
          mirror-1  ONLINE       0     0     0
            ada2p3  ONLINE       0     0     0
            ada3p3  ONLINE       0     0     0

errors: No known data errors

无法从池中删除 vdev,并且如果剩余的冗余足够,则从镜像中删除磁盘是排他的。如果镜像组中只有一个磁盘,该组将不再是镜像,而将成为条带,如果剩余的磁盘发生故障,则会使整个池面临风险。

从三路镜像组中删除一个磁盘

# zpool status
  pool: mypool
 state: ONLINE
  scan: scrub repaired 0 in 0h0m with 0 errors on Fri May 30 08:29:51 2014
config:

        NAME        STATE     READ WRITE CKSUM
        mypool      ONLINE       0     0     0
          mirror-0  ONLINE       0     0     0
            ada0p3  ONLINE       0     0     0
            ada1p3  ONLINE       0     0     0
            ada2p3  ONLINE       0     0     0

errors: No known data errors
# zpool detach mypool ada2p3
# zpool status
  pool: mypool
 state: ONLINE
  scan: scrub repaired 0 in 0h0m with 0 errors on Fri May 30 08:29:51 2014
config:

        NAME        STATE     READ WRITE CKSUM
        mypool      ONLINE       0     0     0
          mirror-0  ONLINE       0     0     0
            ada0p3  ONLINE       0     0     0
            ada1p3  ONLINE       0     0     0

errors: No known data errors

22.3.3. 检查池的状态

池状态很重要。如果驱动器脱机或 ZFS 检测到读、写或校验和错误,相应的错误计数会增加。 status 输出显示了池中每个设备的配置和状态,以及整个池的状态。还显示了需要采取的操作以及有关上次 scrub 的详细信息。

# zpool status
  pool: mypool
 state: ONLINE
  scan: scrub repaired 0 in 2h25m with 0 errors on Sat Sep 14 04:25:50 2013
config:

        NAME        STATE     READ WRITE CKSUM
        mypool      ONLINE       0     0     0
          raidz2-0  ONLINE       0     0     0
            ada0p3  ONLINE       0     0     0
            ada1p3  ONLINE       0     0     0
            ada2p3  ONLINE       0     0     0
            ada3p3  ONLINE       0     0     0
            ada4p3  ONLINE       0     0     0
            ada5p3  ONLINE       0     0     0

errors: No known data errors

22.3.4. 清除错误

检测到错误时,ZFS 会增加读、写或校验和错误计数。使用 zpool clear mypool 清除错误消息并重置计数。清除错误状态对于自动脚本可能很重要,这些脚本在池遇到错误时会向管理员发出警报。如果不清除旧错误,脚本可能无法报告其他错误。

22.3.5. 替换正常运行的设备

可能需要用不同的磁盘替换一个磁盘。替换正常运行的磁盘时,该过程会在替换过程中使旧磁盘保持联机状态。池永远不会进入 degraded 状态,从而降低了数据丢失的风险。运行 zpool replace 会将数据从旧磁盘复制到新磁盘。操作完成后,ZFS 会将旧磁盘从 vdev 中断开连接。如果新磁盘大于旧磁盘,则可以使用新空间来扩展 zpool。参见 扩展池

替换池中正常运行的设备

# zpool status
  pool: mypool
 state: ONLINE
  scan: none requested
config:

        NAME        STATE     READ WRITE CKSUM
        mypool      ONLINE       0     0     0
          mirror-0  ONLINE       0     0     0
            ada0p3  ONLINE       0     0     0
            ada1p3  ONLINE       0     0     0

errors: No known data errors
# zpool replace mypool ada1p3 ada2p3
Make sure to wait until resilvering finishes before rebooting.

When booting from the pool 'zroot', update the boot code on the newly attached disk 'ada2p3'.

Assuming GPT partitioning is used and [.filename]#da0# is the new boot disk, use the following command:

        gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 da0
# gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ada2
# zpool status
  pool: mypool
 state: ONLINE
status: One or more devices is currently being resilvered.  The pool will
        continue to function, possibly in a degraded state.
action: Wait for the resilver to complete.
  scan: resilver in progress since Mon Jun  2 14:21:35 2014
        604M scanned out of 781M at 46.5M/s, 0h0m to go
        604M resilvered, 77.39% done
config:

        NAME             STATE     READ WRITE CKSUM
        mypool           ONLINE       0     0     0
          mirror-0       ONLINE       0     0     0
            ada0p3       ONLINE       0     0     0
            replacing-1  ONLINE       0     0     0
              ada1p3     ONLINE       0     0     0
              ada2p3     ONLINE       0     0     0  (resilvering)

errors: No known data errors
# zpool status
  pool: mypool
 state: ONLINE
  scan: resilvered 781M in 0h0m with 0 errors on Mon Jun  2 14:21:52 2014
config:

        NAME        STATE     READ WRITE CKSUM
        mypool      ONLINE       0     0     0
          mirror-0  ONLINE       0     0     0
            ada0p3  ONLINE       0     0     0
            ada2p3  ONLINE       0     0     0

errors: No known data errors

22.3.6. 处理故障设备

当池中的磁盘发生故障时,该磁盘所属的 vdev 进入 degraded 状态。数据仍然可用,但性能降低,因为 ZFS 从可用冗余中计算丢失的数据。要将 vdev 恢复到完全正常运行的状态,请替换故障的物理设备。然后,ZFS 会被指示开始 resilver 操作。ZFS 会从可用冗余中重新计算故障设备上的数据,并将其写入替换设备。完成之后,vdev 会恢复到 online 状态。

如果 vdev 没有任何冗余,或者如果设备发生故障,并且没有足够的冗余来补偿,则池会进入 faulted 状态。除非有足够的设备可以重新连接池,否则池将无法正常工作,需要从备份中恢复数据。

替换故障磁盘时,故障磁盘的名称会更改为新磁盘的 GUID。如果替换设备具有相同的设备名称,则不需要 zpool replace 的新设备名称参数。

使用 zpool replace 替换故障磁盘

# zpool status
  pool: mypool
 state: DEGRADED
status: One or more devices could not be opened.  Sufficient replicas exist for
        the pool to continue functioning in a degraded state.
action: Attach the missing device and online it using 'zpool online'.
   see: http://illumos.org/msg/ZFS-8000-2Q
  scan: none requested
config:

        NAME                    STATE     READ WRITE CKSUM
        mypool                  DEGRADED     0     0     0
          mirror-0              DEGRADED     0     0     0
            ada0p3              ONLINE       0     0     0
            316502962686821739  UNAVAIL      0     0     0  was /dev/ada1p3

errors: No known data errors
# zpool replace mypool 316502962686821739 ada2p3
# zpool status
  pool: mypool
 state: DEGRADED
status: One or more devices is currently being resilvered.  The pool will
        continue to function, possibly in a degraded state.
action: Wait for the resilver to complete.
  scan: resilver in progress since Mon Jun  2 14:52:21 2014
        641M scanned out of 781M at 49.3M/s, 0h0m to go
        640M resilvered, 82.04% done
config:

        NAME                        STATE     READ WRITE CKSUM
        mypool                      DEGRADED     0     0     0
          mirror-0                  DEGRADED     0     0     0
            ada0p3                  ONLINE       0     0     0
            replacing-1             UNAVAIL      0     0     0
              15732067398082357289  UNAVAIL      0     0     0  was /dev/ada1p3/old
              ada2p3                ONLINE       0     0     0  (resilvering)

errors: No known data errors
# zpool status
  pool: mypool
 state: ONLINE
  scan: resilvered 781M in 0h0m with 0 errors on Mon Jun  2 14:52:38 2014
config:

        NAME        STATE     READ WRITE CKSUM
        mypool      ONLINE       0     0     0
          mirror-0  ONLINE       0     0     0
            ada0p3  ONLINE       0     0     0
            ada2p3  ONLINE       0     0     0

errors: No known data errors

22.3.7. 擦除池

定期 擦除 池,理想情况下至少每月一次。 scrub 操作是磁盘密集型的,会在运行时降低性能。在计划 scrub 时,请避免高需求时期,或使用 vfs.zfs.scrub_delay 来调整 scrub 的相对优先级,以防止它减慢其他工作负载的速度。

# zpool scrub mypool
# zpool status
  pool: mypool
 state: ONLINE
  scan: scrub in progress since Wed Feb 19 20:52:54 2014
        116G scanned out of 8.60T at 649M/s, 3h48m to go
        0 repaired, 1.32% done
config:

        NAME        STATE     READ WRITE CKSUM
        mypool      ONLINE       0     0     0
          raidz2-0  ONLINE       0     0     0
            ada0p3  ONLINE       0     0     0
            ada1p3  ONLINE       0     0     0
            ada2p3  ONLINE       0     0     0
            ada3p3  ONLINE       0     0     0
            ada4p3  ONLINE       0     0     0
            ada5p3  ONLINE       0     0     0

errors: No known data errors

如果需要取消擦除操作,请运行 zpool scrub -s mypool

22.3.8. 自修复

与数据块一起存储的校验和使文件系统能够自修复。此功能将自动修复校验和与存储在存储池中另一个设备上的记录不匹配的数据。例如,一个包含两个磁盘的镜像配置,其中一个驱动器开始出现故障,无法正确存储数据。当数据很长时间没有访问时,情况会更糟,例如长期归档存储。传统文件系统需要运行检查和修复数据的命令,例如 fsck(8)。这些命令需要时间,在严重的情况下,管理员必须决定要执行哪种修复操作。当 ZFS 检测到校验和不匹配的数据块时,它会尝试从镜像磁盘中读取数据。如果该磁盘可以提供正确的数据,则 ZFS 会将数据提供给应用程序,并更正校验和错误的磁盘上的数据。这会在正常的池操作过程中发生,无需系统管理员进行任何交互。

以下示例通过创建磁盘 /dev/ada0/dev/ada1 的镜像池来展示这种自修复行为。

# zpool create healer mirror /dev/ada0 /dev/ada1
# zpool status healer
  pool: healer
 state: ONLINE
  scan: none requested
config:

    NAME        STATE     READ WRITE CKSUM
    healer      ONLINE       0     0     0
      mirror-0  ONLINE       0     0     0
       ada0     ONLINE       0     0     0
       ada1     ONLINE       0     0     0

errors: No known data errors
# zpool list
NAME     SIZE  ALLOC   FREE   CKPOINT  EXPANDSZ   FRAG   CAP  DEDUP  HEALTH  ALTROOT
healer   960M  92.5K   960M         -         -     0%    0%  1.00x  ONLINE  -

将一些重要数据复制到池中,以使用自修复功能保护数据免受错误的影响,并创建池的校验和以供以后比较。

# cp /some/important/data /healer
# zfs list
NAME     SIZE  ALLOC   FREE    CAP  DEDUP  HEALTH  ALTROOT
healer   960M  67.7M   892M     7%  1.00x  ONLINE  -
# sha1 /healer > checksum.txt
# cat checksum.txt
SHA1 (/healer) = 2753eff56d77d9a536ece6694bf0a82740344d1f

通过将随机数据写入镜像中一个磁盘的开头来模拟数据损坏。为了防止 ZFS 在检测到数据损坏时进行修复,请在损坏之前导出池,并在之后重新导入池。

这是一个危险的操作,可能会破坏重要数据,这里仅用于演示。请勿尝试在存储池的正常操作过程中执行此操作。也不应在包含其他分区中未使用 ZFS 的文件系统的磁盘上运行此示例,也不应该对这些示例进行故意损坏。不要使用除池中包含的名称以外的任何其他磁盘设备名称。确保池的适当备份存在,并在运行命令之前测试备份!

# zpool export healer
# dd if=/dev/random of=/dev/ada1 bs=1m count=200
200+0 records in
200+0 records out
209715200 bytes transferred in 62.992162 secs (3329227 bytes/sec)
# zpool import healer

池状态显示一个设备发生了错误。请注意,从池中读取数据的应用程序没有收到任何不正确的数据。ZFS 提供了来自具有正确校验和的 ada0 设备的数据。要查找校验和错误的设备,请查找 CKSUM 列包含非零值的设备。

# zpool status healer
    pool: healer
   state: ONLINE
  status: One or more devices has experienced an unrecoverable error.  An
          attempt was made to correct the error.  Applications are unaffected.
  action: Determine if the device needs to be replaced, and clear the errors
          using 'zpool clear' or replace the device with 'zpool replace'.
     see: http://illumos.org/msg/ZFS-8000-4J
    scan: none requested
  config:

      NAME        STATE     READ WRITE CKSUM
      healer      ONLINE       0     0     0
        mirror-0  ONLINE       0     0     0
         ada0     ONLINE       0     0     0
         ada1     ONLINE       0     0     1

errors: No known data errors

ZFS 检测到错误并通过使用未受影响的 ada0 镜像磁盘中的冗余来处理错误。与原始校验和的比较将揭示池是否再次一致。

# sha1 /healer >> checksum.txt
# cat checksum.txt
SHA1 (/healer) = 2753eff56d77d9a536ece6694bf0a82740344d1f
SHA1 (/healer) = 2753eff56d77d9a536ece6694bf0a82740344d1f

在有意篡改之前和之后生成校验和,同时池数据仍然匹配。这展示了当校验和不同时,ZFS 如何能够自动检测和纠正任何错误。请注意,这需要池中存在足够的冗余。由单个设备组成的池没有自修复功能。这也是校验和在 ZFS 中如此重要的原因;不要出于任何原因禁用它们。ZFS 不需要 fsck(8) 或类似的文件系统一致性检查程序来检测和纠正此问题,并在出现问题时使池保持可用。现在需要擦除操作来覆盖 ada1 上的损坏数据。

# zpool scrub healer
# zpool status healer
  pool: healer
 state: ONLINE
status: One or more devices has experienced an unrecoverable error.  An
            attempt was made to correct the error.  Applications are unaffected.
action: Determine if the device needs to be replaced, and clear the errors
            using 'zpool clear' or replace the device with 'zpool replace'.
   see: http://illumos.org/msg/ZFS-8000-4J
  scan: scrub in progress since Mon Dec 10 12:23:30 2012
        10.4M scanned out of 67.0M at 267K/s, 0h3m to go
        9.63M repaired, 15.56% done
config:

    NAME        STATE     READ WRITE CKSUM
    healer      ONLINE       0     0     0
      mirror-0  ONLINE       0     0     0
       ada0     ONLINE       0     0     0
       ada1     ONLINE       0     0   627  (repairing)

errors: No known data errors

擦除操作从 ada0 读取数据,并重写 ada1 上校验和错误的任何数据,如 zpool status 输出的 (repairing) 所示。操作完成后,池状态将更改为

# zpool status healer
  pool: healer
 state: ONLINE
status: One or more devices has experienced an unrecoverable error.  An
        attempt was made to correct the error.  Applications are unaffected.
action: Determine if the device needs to be replaced, and clear the errors
             using 'zpool clear' or replace the device with 'zpool replace'.
   see: http://illumos.org/msg/ZFS-8000-4J
  scan: scrub repaired 66.5M in 0h2m with 0 errors on Mon Dec 10 12:26:25 2012
config:

    NAME        STATE     READ WRITE CKSUM
    healer      ONLINE       0     0     0
      mirror-0  ONLINE       0     0     0
       ada0     ONLINE       0     0     0
       ada1     ONLINE       0     0 2.72K

errors: No known data errors

在擦除操作完成后,所有数据都从 ada0 同步到 ada1,通过运行 zpool clear 从池状态中 清除 错误消息。

# zpool clear healer
# zpool status healer
  pool: healer
 state: ONLINE
  scan: scrub repaired 66.5M in 0h2m with 0 errors on Mon Dec 10 12:26:25 2012
config:

    NAME        STATE     READ WRITE CKSUM
    healer      ONLINE       0     0     0
      mirror-0  ONLINE       0     0     0
       ada0     ONLINE       0     0     0
       ada1     ONLINE       0     0     0

errors: No known data errors

池现在恢复到完全正常运行的状态,所有错误计数现在都为零。

22.3.9. 扩展池

每个 vdev 中最小的设备限制了冗余池的可使用大小。用更大的设备替换最小的设备。完成 替换resilver 操作后,池可以扩展到使用新设备的容量。例如,考虑一个 1 TB 驱动器和一个 2 TB 驱动器的镜像。可使用空间为 1 TB。当用另一个 2 TB 驱动器替换 1 TB 驱动器时,resilvering 过程会将现有数据复制到新驱动器上。由于两个设备现在都具有 2 TB 的容量,因此镜像的可用空间会扩展到 2 TB。

通过对每个设备使用 zpool online -e 来启动扩展。扩展所有设备后,额外的空间将变得对池可用。

22.3.10. 导入和导出池

在将池移动到另一个系统之前,导出池。ZFS 会卸载所有数据集,并将每个设备标记为已导出,但仍然锁定以防止其他磁盘使用。这允许在其他机器、支持 ZFS 的其他操作系统,甚至不同的硬件架构(有一些注意事项,请参见 zpool(8))上导入池。当数据集具有打开的文件时,使用 zpool export -f 强制导出池。谨慎使用此命令。数据集会被强行卸载,这可能会导致在那些数据集中有打开文件的应用程序中出现意外行为。

导出未使用的池

# zpool export mypool

导入池会自动挂载数据集。如果不需要这种行为,请使用zpool import -N来阻止它。zpool import -o设置此特定导入的临时属性。zpool import altroot=允许导入一个使用基本挂载点而不是文件系统根目录的池。如果池上次在不同的系统上使用,并且没有正确导出,请使用zpool import -f强制导入。zpool import -a导入所有似乎没有被其他系统使用的池。

列出所有可用于导入的池

# zpool import
   pool: mypool
     id: 9930174748043525076
  state: ONLINE
 action: The pool can be imported using its name or numeric identifier.
 config:

        mypool      ONLINE
          ada2p3    ONLINE

使用备用根目录导入池

# zpool import -o altroot=/mnt mypool
# zfs list
zfs list
NAME                 USED  AVAIL  REFER  MOUNTPOINT
mypool               110K  47.0G    31K  /mnt/mypool

22.3.11. 升级存储池

在升级 FreeBSD 之后,或者如果从使用旧版本的系统导入池,请手动将池升级到最新的 ZFS 版本,以支持新功能。在升级之前,请考虑池是否需要在旧系统上导入。升级是单向过程。升级旧池是可能的,但降级具有新功能的池是不可能的。

将 v28 池升级以支持功能标志

# zpool status
  pool: mypool
 state: ONLINE
status: The pool is formatted using a legacy on-disk format.  The pool can
        still be used, but some features are unavailable.
action: Upgrade the pool using 'zpool upgrade'.  Once this is done, the
        pool will no longer be accessible on software that does not support feat
        flags.
  scan: none requested
config:

        NAME        STATE     READ WRITE CKSUM
        mypool      ONLINE       0     0     0
          mirror-0  ONLINE       0     0     0
	    ada0    ONLINE       0     0     0
	    ada1    ONLINE       0     0     0

errors: No known data errors
# zpool upgrade
This system supports ZFS pool feature flags.

The following pools are formatted with legacy version numbers and are upgraded to use feature flags.
After being upgraded, these pools will no longer be accessible by software that does not support feature flags.

VER  POOL
---  ------------
28   mypool

Use 'zpool upgrade -v' for a list of available legacy versions.
Every feature flags pool has all supported features enabled.
# zpool upgrade mypool
This system supports ZFS pool feature flags.

Successfully upgraded 'mypool' from version 28 to feature flags.
Enabled the following features on 'mypool':
  async_destroy
  empty_bpobj
  lz4_compress
  multi_vdev_crash_dump

zpool upgrade完成之前,ZFS 的新功能将不可用。使用zpool upgrade -v查看升级提供的哪些新功能,以及哪些功能已经支持。

将池升级以支持新的功能标志

# zpool status
  pool: mypool
 state: ONLINE
status: Some supported features are not enabled on the pool. The pool can
        still be used, but some features are unavailable.
action: Enable all features using 'zpool upgrade'. Once this is done,
        the pool may no longer be accessible by software that does not support
        the features. See zpool-features(7) for details.
  scan: none requested
config:

        NAME        STATE     READ WRITE CKSUM
        mypool      ONLINE       0     0     0
          mirror-0  ONLINE       0     0     0
	    ada0    ONLINE       0     0     0
	    ada1    ONLINE       0     0     0

errors: No known data errors
# zpool upgrade
This system supports ZFS pool feature flags.

All pools are formatted using feature flags.

Some supported features are not enabled on the following pools. Once a
feature is enabled the pool may become incompatible with software
that does not support the feature. See zpool-features(7) for details.

POOL  FEATURE
---------------
zstore
      multi_vdev_crash_dump
      spacemap_histogram
      enabled_txg
      hole_birth
      extensible_dataset
      bookmarks
      filesystem_limits
# zpool upgrade mypool
This system supports ZFS pool feature flags.

Enabled the following features on 'mypool':
  spacemap_histogram
  enabled_txg
  hole_birth
  extensible_dataset
  bookmarks
  filesystem_limits

更新从池启动的系统的引导代码,以支持新的池版本。在包含引导代码的分区上使用gpart bootcode。两种类型的引导代码可用,具体取决于系统的启动方式:GPT(最常见的选项)和 EFI(对于更新的系统)。

对于使用 GPT 的传统引导,请使用以下命令

# gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ada1

对于使用 EFI 引导的系统,请执行以下命令

# gpart bootcode -p /boot/boot1.efifat -i 1 ada1

将引导代码应用于池中的所有可引导磁盘。有关更多信息,请参见gpart(8)

22.3.12. 显示已记录的池历史记录

ZFS 记录更改池的命令,包括创建数据集、更改属性或替换磁盘。查看有关池创建的历史记录非常有用,查看哪个用户何时执行了特定操作也很有用。历史记录不会保存在日志文件中,而是池本身的一部分。用于查看此历史记录的命令名为zpool history

# zpool history
History for 'tank':
2013-02-26.23:02:35 zpool create tank mirror /dev/ada0 /dev/ada1
2013-02-27.18:50:58 zfs set atime=off tank
2013-02-27.18:51:09 zfs set checksum=fletcher4 tank
2013-02-27.18:51:18 zfs create tank/backup

输出显示zpoolzfs命令以某种方式更改了池,以及时间戳。zfs list之类的命令不包括在内。当不指定池名称时,ZFS 会显示所有池的历史记录。

当提供-i-l选项时,zpool history可以显示更多信息。-i显示用户发起的事件以及内部记录的 ZFS 事件。

# zpool history -i
History for 'tank':
2013-02-26.23:02:35 [internal pool create txg:5] pool spa 28; zfs spa 28; zpl 5;uts  9.1-RELEASE 901000 amd64
2013-02-27.18:50:53 [internal property set txg:50] atime=0 dataset = 21
2013-02-27.18:50:58 zfs set atime=off tank
2013-02-27.18:51:04 [internal property set txg:53] checksum=7 dataset = 21
2013-02-27.18:51:09 zfs set checksum=fletcher4 tank
2013-02-27.18:51:13 [internal create txg:55] dataset = 39
2013-02-27.18:51:18 zfs create tank/backup

通过添加-l来显示更多详细信息。以长格式显示历史记录,包括用户发出命令的用户名和发生更改的主机名等信息。

# zpool history -l
History for 'tank':
2013-02-26.23:02:35 zpool create tank mirror /dev/ada0 /dev/ada1 [user 0 (root) on :global]
2013-02-27.18:50:58 zfs set atime=off tank [user 0 (root) on myzfsbox:global]
2013-02-27.18:51:09 zfs set checksum=fletcher4 tank [user 0 (root) on myzfsbox:global]
2013-02-27.18:51:18 zfs create tank/backup [user 0 (root) on myzfsbox:global]

输出显示root用户使用磁盘/dev/ada0/dev/ada1创建了镜像池。主机名myzfsbox也显示在池创建后的命令中。当从一个系统导出池并在另一个系统上导入时,主机名显示变得很重要。可以通过为每个命令记录的主机名来区分在其他系统上发出的命令。

将两个选项都组合到zpool history中,以提供任何给定池的尽可能详细的信息。池历史记录在跟踪执行的操作或需要更详细的输出以进行调试时提供有价值的信息。

22.3.13. 性能监控

内置的监控系统可以实时显示池的 I/O 统计信息。它显示池的可用空间和已用空间量、每秒执行的读写操作以及使用的 I/O 带宽。默认情况下,ZFS 会监控和显示系统中的所有池。提供池名称以将监控限制为该池。一个基本示例

# zpool iostat
               capacity     operations    bandwidth
pool        alloc   free   read  write   read  write
----------  -----  -----  -----  -----  -----  -----
data         288G  1.53T      2     11  11.3K  57.1K

要持续查看 I/O 活动,请指定一个数字作为最后一个参数,指示更新之间等待的间隔(以秒为单位)。每隔一段时间就会打印下一行统计信息。按Ctrl+C停止此持续监控。在命令行上的间隔之后给出第二个数字以指定要显示的统计信息总数。

使用-v显示更详细的 I/O 统计信息。池中的每个设备都会显示一行统计信息。这对于查看对每个设备执行的读写操作非常有用,可以帮助确定是否有任何单个设备减慢了池的速度。此示例显示了一个具有两个设备的镜像池

# zpool iostat -v
                            capacity     operations    bandwidth
pool                     alloc   free   read  write   read  write
-----------------------  -----  -----  -----  -----  -----  -----
data                      288G  1.53T      2     12  9.23K  61.5K
  mirror                  288G  1.53T      2     12  9.23K  61.5K
    ada1                     -      -      0      4  5.61K  61.7K
    ada2                     -      -      1      4  5.04K  61.7K
-----------------------  -----  -----  -----  -----  -----  -----

22.3.14. 拆分存储池

ZFS 可以将一个或多个镜像 vdev 组成的池拆分为两个池。除非另有说明,否则 ZFS 会分离每个镜像的最后一个成员,并创建一个包含相同数据的池。请务必先使用-n对操作进行试运行。这将显示请求的操作的详细信息,而不会实际执行它。这有助于确认操作将按用户预期的方式进行。

22.4. zfs 管理

zfs实用程序可以创建、销毁和管理池中所有现有的 ZFS 数据集。要管理池本身,请使用zpool

22.4.1. 创建和销毁数据集

与传统的磁盘和卷管理程序不同,ZFS 中的空间是预分配的。在传统的系统中,在分区和分配空间后,无法在不添加新磁盘的情况下添加新的系统。在 ZFS 中,可以随时创建新的系统。每个数据集都具有属性,包括压缩、重复数据删除、缓存和配额等功能,以及其他有用的属性,如只读、区分大小写、网络文件共享和挂载点。可以在每个数据集内嵌套数据集,子数据集将从其祖先继承属性。 委派复制快照监狱允许管理和销毁每个数据集作为单元。为每种不同类型或一组文件创建单独的数据集有其优势。拥有大量数据集的缺点是某些命令(如zfs list)会变慢,以及挂载数百甚至数千个数据集会减慢 FreeBSD 的启动过程。

创建一个新的数据集,并在其上启用LZ4 压缩

# zfs list
NAME                  USED  AVAIL  REFER  MOUNTPOINT
mypool                781M  93.2G   144K  none
mypool/ROOT           777M  93.2G   144K  none
mypool/ROOT/default   777M  93.2G   777M  /
mypool/tmp            176K  93.2G   176K  /tmp
mypool/usr            616K  93.2G   144K  /usr
mypool/usr/home       184K  93.2G   184K  /usr/home
mypool/usr/ports      144K  93.2G   144K  /usr/ports
mypool/usr/src        144K  93.2G   144K  /usr/src
mypool/var           1.20M  93.2G   608K  /var
mypool/var/crash      148K  93.2G   148K  /var/crash
mypool/var/log        178K  93.2G   178K  /var/log
mypool/var/mail       144K  93.2G   144K  /var/mail
mypool/var/tmp        152K  93.2G   152K  /var/tmp
# zfs create -o compress=lz4 mypool/usr/mydataset
# zfs list
NAME                   USED  AVAIL  REFER  MOUNTPOINT
mypool                 781M  93.2G   144K  none
mypool/ROOT            777M  93.2G   144K  none
mypool/ROOT/default    777M  93.2G   777M  /
mypool/tmp             176K  93.2G   176K  /tmp
mypool/usr             704K  93.2G   144K  /usr
mypool/usr/home        184K  93.2G   184K  /usr/home
mypool/usr/mydataset  87.5K  93.2G  87.5K  /usr/mydataset
mypool/usr/ports       144K  93.2G   144K  /usr/ports
mypool/usr/src         144K  93.2G   144K  /usr/src
mypool/var            1.20M  93.2G   610K  /var
mypool/var/crash       148K  93.2G   148K  /var/crash
mypool/var/log         178K  93.2G   178K  /var/log
mypool/var/mail        144K  93.2G   144K  /var/mail
mypool/var/tmp         152K  93.2G   152K  /var/tmp

销毁数据集比删除数据集上的文件快得多,因为它不涉及扫描文件和更新相应的元数据。

销毁创建的数据集

# zfs list
NAME                   USED  AVAIL  REFER  MOUNTPOINT
mypool                 880M  93.1G   144K  none
mypool/ROOT            777M  93.1G   144K  none
mypool/ROOT/default    777M  93.1G   777M  /
mypool/tmp             176K  93.1G   176K  /tmp
mypool/usr             101M  93.1G   144K  /usr
mypool/usr/home        184K  93.1G   184K  /usr/home
mypool/usr/mydataset   100M  93.1G   100M  /usr/mydataset
mypool/usr/ports       144K  93.1G   144K  /usr/ports
mypool/usr/src         144K  93.1G   144K  /usr/src
mypool/var            1.20M  93.1G   610K  /var
mypool/var/crash       148K  93.1G   148K  /var/crash
mypool/var/log         178K  93.1G   178K  /var/log
mypool/var/mail        144K  93.1G   144K  /var/mail
mypool/var/tmp         152K  93.1G   152K  /var/tmp
# zfs destroy mypool/usr/mydataset
# zfs list
NAME                  USED  AVAIL  REFER  MOUNTPOINT
mypool                781M  93.2G   144K  none
mypool/ROOT           777M  93.2G   144K  none
mypool/ROOT/default   777M  93.2G   777M  /
mypool/tmp            176K  93.2G   176K  /tmp
mypool/usr            616K  93.2G   144K  /usr
mypool/usr/home       184K  93.2G   184K  /usr/home
mypool/usr/ports      144K  93.2G   144K  /usr/ports
mypool/usr/src        144K  93.2G   144K  /usr/src
mypool/var           1.21M  93.2G   612K  /var
mypool/var/crash      148K  93.2G   148K  /var/crash
mypool/var/log        178K  93.2G   178K  /var/log
mypool/var/mail       144K  93.2G   144K  /var/mail
mypool/var/tmp        152K  93.2G   152K  /var/tmp

在现代版本的 ZFS 中,zfs destroy是异步的,并且空闲空间可能需要几分钟才能出现在池中。使用zpool get freeing poolname查看freeing属性,该属性显示哪些数据集的块正在后台释放。如果存在子数据集(如快照或其他数据集),则无法销毁父数据集。要销毁数据集及其子数据集,请使用-r递归销毁数据集及其子数据集。使用-n -v列出此操作销毁的数据集和快照,而不会实际销毁任何内容。销毁快照回收的空间也会显示。

22.4.2. 创建和销毁卷

卷是一种特殊的数据集类型。它不是作为系统挂载,而是作为/dev/zvol/poolname/dataset下的块设备公开。这允许将卷用于其他系统,支持虚拟机的磁盘,或使用 iSCSI 或 HAST 等协议将其提供给其他网络主机。

使用任何系统格式化卷,或者不使用系统格式化卷以存储原始数据。对用户而言,卷看起来像普通的磁盘。将普通的系统放在这些zvol上可以提供普通磁盘或系统没有的功能。例如,在 250 MB 卷上使用压缩属性可以创建压缩的 FAT 系统。

# zfs create -V 250m -o compression=on tank/fat32
# zfs list tank
NAME USED AVAIL REFER MOUNTPOINT
tank 258M  670M   31K /tank
# newfs_msdos -F32 /dev/zvol/tank/fat32
# mount -t msdosfs /dev/zvol/tank/fat32 /mnt
# df -h /mnt | grep fat32
Filesystem           Size Used Avail Capacity Mounted on
/dev/zvol/tank/fat32 249M  24k  249M     0%   /mnt
# mount | grep fat32
/dev/zvol/tank/fat32 on /mnt (msdosfs, local)

销毁卷与销毁常规系统数据集非常相似。操作几乎是瞬时的,但可能需要几分钟才能在后台回收空闲空间。

22.4.3. 重命名数据集

要更改数据集的名称,请使用zfs rename。要更改数据集的父级,请也使用此命令。将数据集重命名为具有不同父级数据集将更改从父级数据集继承的那些属性的值。重命名数据集将取消挂载然后重新挂载到新位置(从新父级数据集继承)。要防止这种行为,请使用-u

重命名数据集并将其移动到不同的父级数据集下

# zfs list
NAME                   USED  AVAIL  REFER  MOUNTPOINT
mypool                 780M  93.2G   144K  none
mypool/ROOT            777M  93.2G   144K  none
mypool/ROOT/default    777M  93.2G   777M  /
mypool/tmp             176K  93.2G   176K  /tmp
mypool/usr             704K  93.2G   144K  /usr
mypool/usr/home        184K  93.2G   184K  /usr/home
mypool/usr/mydataset  87.5K  93.2G  87.5K  /usr/mydataset
mypool/usr/ports       144K  93.2G   144K  /usr/ports
mypool/usr/src         144K  93.2G   144K  /usr/src
mypool/var            1.21M  93.2G   614K  /var
mypool/var/crash       148K  93.2G   148K  /var/crash
mypool/var/log         178K  93.2G   178K  /var/log
mypool/var/mail        144K  93.2G   144K  /var/mail
mypool/var/tmp         152K  93.2G   152K  /var/tmp
# zfs rename mypool/usr/mydataset mypool/var/newname
# zfs list
NAME                  USED  AVAIL  REFER  MOUNTPOINT
mypool                780M  93.2G   144K  none
mypool/ROOT           777M  93.2G   144K  none
mypool/ROOT/default   777M  93.2G   777M  /
mypool/tmp            176K  93.2G   176K  /tmp
mypool/usr            616K  93.2G   144K  /usr
mypool/usr/home       184K  93.2G   184K  /usr/home
mypool/usr/ports      144K  93.2G   144K  /usr/ports
mypool/usr/src        144K  93.2G   144K  /usr/src
mypool/var           1.29M  93.2G   614K  /var
mypool/var/crash      148K  93.2G   148K  /var/crash
mypool/var/log        178K  93.2G   178K  /var/log
mypool/var/mail       144K  93.2G   144K  /var/mail
mypool/var/newname   87.5K  93.2G  87.5K  /var/newname
mypool/var/tmp        152K  93.2G   152K  /var/tmp

重命名快照使用相同的命令。由于快照的性质,重命名无法更改其父级数据集。要重命名递归快照,请指定-r;这也会重命名子数据集中的所有同名快照。

# zfs list -t snapshot
NAME                                USED  AVAIL  REFER  MOUNTPOINT
mypool/var/newname@first_snapshot      0      -  87.5K  -
# zfs rename mypool/var/newname@first_snapshot new_snapshot_name
# zfs list -t snapshot
NAME                                   USED  AVAIL  REFER  MOUNTPOINT
mypool/var/newname@new_snapshot_name      0      -  87.5K  -

22.4.4. 设置数据集属性

每个 ZFS 数据集都具有控制其行为的属性。大多数属性都是从父级数据集自动继承的,但可以在本地覆盖。使用zfs set property=value dataset设置数据集上的属性。大多数属性都有一组有限的有效值,zfs get将显示每个可能的属性和有效值。使用zfs inherit将大多数属性恢复为其继承的值。用户定义的属性也是可能的。它们成为数据集配置的一部分,并提供有关数据集或其内容的更多信息。为了区分这些自定义属性与作为 ZFS 一部分提供的属性,请使用冒号 (:) 为属性创建一个自定义命名空间。

# zfs set custom:costcenter=1234 tank
# zfs get custom:costcenter tank
NAME PROPERTY           VALUE SOURCE
tank custom:costcenter  1234  local

要删除自定义属性,请使用带有-rzfs inherit。如果自定义属性在任何父级数据集中都没有定义,则此选项会将其删除(但池的历史记录仍然会记录更改)。

# zfs inherit -r custom:costcenter tank
# zfs get custom:costcenter tank
NAME    PROPERTY           VALUE              SOURCE
tank    custom:costcenter  -                  -
# zfs get all tank | grep custom:costcenter
#

22.4.4.1. 获取和设置共享属性

两个常用的有用的数据集属性是 NFS 和 SMB 共享选项。设置这些选项定义 ZFS 是否以及如何共享网络上的数据集。目前,FreeBSD 仅支持设置 NFS 共享。要获取共享的当前状态,请输入

# zfs get sharenfs mypool/usr/home
NAME             PROPERTY  VALUE    SOURCE
mypool/usr/home  sharenfs  on       local
# zfs get sharesmb mypool/usr/home
NAME             PROPERTY  VALUE    SOURCE
mypool/usr/home  sharesmb  off      local

要启用数据集共享,请输入

#  zfs set sharenfs=on mypool/usr/home

设置通过 NFS 共享数据集的其他选项,例如-alldirs-maproot-network。要在通过 NFS 共享的数据集上设置选项,请输入

#  zfs set sharenfs="-alldirs,-maproot=root,-network=192.168.1.0/24" mypool/usr/home

22.4.5. 管理快照

快照 是 ZFS 最强大的功能之一。快照提供数据集的只读、时间点副本。使用写时复制 (COW),ZFS 通过保留磁盘上数据的旧版本来快速创建快照。如果不存在快照,ZFS 会在数据被重写或删除时回收空间以供将来使用。快照通过仅记录当前数据集与先前版本之间的差异来保留磁盘空间。允许对整个数据集进行快照,而不是对单个文件或目录进行快照。来自数据集的快照会复制其中包含的所有内容。这包括文件系统属性、文件、目录、权限等等。快照在首次创建时不会使用额外的空间,但会随着它们引用的块发生变化而占用空间。使用 -r 拍摄的递归快照会在数据集及其子级上创建相同名称的快照,从而提供对文件系统的始终如一的特定时间点快照。当应用程序在相关数据集上或依赖于彼此的文件时,这可能很重要。如果没有快照,备份将包含来自不同时间的文件的副本。

ZFS 中的快照提供了许多其他具有快照功能的文件系统所不具备的功能。快照使用的典型示例是在执行有风险的操作(例如软件安装或系统升级)时快速备份文件系统当前状态的一种方法。如果操作失败,回滚到快照会将系统恢复到创建快照时的相同状态。如果升级成功,请删除快照以释放空间。如果没有快照,升级失败通常需要恢复备份,这很繁琐、耗时,并且可能需要系统不可用期间的停机时间。回滚到快照速度很快,即使系统在正常运行中,也几乎没有停机时间。考虑到从备份中复制数据所需的时间,对于多 TB 存储系统而言,节省的时间是巨大的。快照不能替代对池的完整备份,但它提供了一种快速简便的方法来存储特定时间的数据集副本。

22.4.5.1. 创建快照

要创建快照,请使用 zfs snapshot dataset@snapshotname。添加 -r 会递归地创建快照,所有子数据集都具有相同名称。

创建整个池的递归快照

# zfs list -t all
NAME                                   USED  AVAIL  REFER  MOUNTPOINT
mypool                                 780M  93.2G   144K  none
mypool/ROOT                            777M  93.2G   144K  none
mypool/ROOT/default                    777M  93.2G   777M  /
mypool/tmp                             176K  93.2G   176K  /tmp
mypool/usr                             616K  93.2G   144K  /usr
mypool/usr/home                        184K  93.2G   184K  /usr/home
mypool/usr/ports                       144K  93.2G   144K  /usr/ports
mypool/usr/src                         144K  93.2G   144K  /usr/src
mypool/var                            1.29M  93.2G   616K  /var
mypool/var/crash                       148K  93.2G   148K  /var/crash
mypool/var/log                         178K  93.2G   178K  /var/log
mypool/var/mail                        144K  93.2G   144K  /var/mail
mypool/var/newname                    87.5K  93.2G  87.5K  /var/newname
mypool/var/newname@new_snapshot_name      0      -  87.5K  -
mypool/var/tmp                         152K  93.2G   152K  /var/tmp
# zfs snapshot -r mypool@my_recursive_snapshot
# zfs list -t snapshot
NAME                                        USED  AVAIL  REFER  MOUNTPOINT
mypool@my_recursive_snapshot                   0      -   144K  -
mypool/ROOT@my_recursive_snapshot              0      -   144K  -
mypool/ROOT/default@my_recursive_snapshot      0      -   777M  -
mypool/tmp@my_recursive_snapshot               0      -   176K  -
mypool/usr@my_recursive_snapshot               0      -   144K  -
mypool/usr/home@my_recursive_snapshot          0      -   184K  -
mypool/usr/ports@my_recursive_snapshot         0      -   144K  -
mypool/usr/src@my_recursive_snapshot           0      -   144K  -
mypool/var@my_recursive_snapshot               0      -   616K  -
mypool/var/crash@my_recursive_snapshot         0      -   148K  -
mypool/var/log@my_recursive_snapshot           0      -   178K  -
mypool/var/mail@my_recursive_snapshot          0      -   144K  -
mypool/var/newname@new_snapshot_name           0      -  87.5K  -
mypool/var/newname@my_recursive_snapshot       0      -  87.5K  -
mypool/var/tmp@my_recursive_snapshot           0      -   152K  -

正常 zfs list 操作不会显示快照。要列出快照,请将 -t snapshot 附加到 zfs list-t all 会显示文件系统和快照。

快照不会直接挂载,在 MOUNTPOINT 列中不显示路径。ZFS 不会在 AVAIL 列中提及可用磁盘空间,因为快照在创建后是只读的。将快照与原始数据集进行比较

# zfs list -rt all mypool/usr/home
NAME                                    USED  AVAIL  REFER  MOUNTPOINT
mypool/usr/home                         184K  93.2G   184K  /usr/home
mypool/usr/home@my_recursive_snapshot      0      -   184K  -

将数据集和快照一起显示揭示了快照在 COW 模式下如何工作。它们会保存所做的更改(增量),而不是再次保存完整的文件系统内容。这意味着快照在进行更改时占用很少的空间。通过将文件复制到数据集,然后创建第二个快照,可以更仔细地观察空间使用情况

# cp /etc/passwd /var/tmp
# zfs snapshot mypool/var/tmp@after_cp
# zfs list -rt all mypool/var/tmp
NAME                                   USED  AVAIL  REFER  MOUNTPOINT
mypool/var/tmp                         206K  93.2G   118K  /var/tmp
mypool/var/tmp@my_recursive_snapshot    88K      -   152K  -
mypool/var/tmp@after_cp                   0      -   118K  -

第二个快照包含复制操作后对数据集的更改。这会产生巨大的空间节省。请注意,快照 mypool/var/tmp@my_recursive_snapshot 的大小也在 USED 列中发生了变化,以显示其自身与之后拍摄的快照之间的更改。

22.4.5.2. 比较快照

ZFS 提供了一个内置命令来比较两个快照之间内容的差异。当用户想要查看文件系统随时间变化的情况时,这对于大量快照来说非常有用。例如,zfs diff 允许用户查找仍然包含意外删除文件的最新快照。对上一节中创建的两个快照执行此操作会产生以下输出

# zfs list -rt all mypool/var/tmp
NAME                                   USED  AVAIL  REFER  MOUNTPOINT
mypool/var/tmp                         206K  93.2G   118K  /var/tmp
mypool/var/tmp@my_recursive_snapshot    88K      -   152K  -
mypool/var/tmp@after_cp                   0      -   118K  -
# zfs diff mypool/var/tmp@my_recursive_snapshot
M       /var/tmp/
+       /var/tmp/passwd

该命令列出了指定快照(在本例中为 mypool/var/tmp@my_recursive_snapshot)与实时文件系统之间的更改。第一列显示更改类型

+

添加路径或文件。

-

删除路径或文件。

M

修改路径或文件。

R

重命名路径或文件。

将输出与表格进行比较,可以清楚地看到 ZFS 在创建快照 mypool/var/tmp@my_recursive_snapshot 后添加了 passwd。这也导致了挂载在 /var/tmp 上的父目录的修改。

在使用 ZFS 复制功能将数据集传输到其他主机以进行备份时,比较两个快照很有用。

通过提供两个数据集的完整数据集名称和快照名称来比较两个快照

# cp /var/tmp/passwd /var/tmp/passwd.copy
# zfs snapshot mypool/var/tmp@diff_snapshot
# zfs diff mypool/var/tmp@my_recursive_snapshot mypool/var/tmp@diff_snapshot
M       /var/tmp/
+       /var/tmp/passwd
+       /var/tmp/passwd.copy
# zfs diff mypool/var/tmp@my_recursive_snapshot mypool/var/tmp@after_cp
M       /var/tmp/
+       /var/tmp/passwd

备份管理员可以比较从发送主机接收的两个快照,并确定数据集的实际更改。有关详细信息,请参阅 复制 部分。

22.4.5.3. 快照回滚

只要至少有一个快照可用,就可以随时回滚到它。这种情况最常见的是,当数据集的当前状态不再有效或更喜欢旧版本时。本地开发测试出错、系统更新失败导致系统功能受损或需要恢复已删除的文件或目录,这些都是非常常见的事件。要回滚快照,请使用 zfs rollback snapshotname。如果存在很多更改,则操作将需要很长时间。在此期间,数据集始终保持一致状态,就像符合 ACID 原则的数据库正在执行回滚一样。这在数据集处于活动状态并可访问时发生,无需停机。回滚到快照后,数据集将具有创建快照时所具有的相同状态。回滚到快照会丢弃该数据集中不属于快照的所有其他数据。在回滚到以前的快照之前,对数据集的当前状态进行快照是一个好主意,因为可能以后还需要某些数据。这样,用户可以在快照之间来回回滚,而不会丢失仍然有价值的数据。

在第一个示例中,由于粗心的 rm 操作删除了比预期更多的数据,因此回滚快照。

# zfs list -rt all mypool/var/tmp
NAME                                   USED  AVAIL  REFER  MOUNTPOINT
mypool/var/tmp                         262K  93.2G   120K  /var/tmp
mypool/var/tmp@my_recursive_snapshot    88K      -   152K  -
mypool/var/tmp@after_cp               53.5K      -   118K  -
mypool/var/tmp@diff_snapshot              0      -   120K  -
# ls /var/tmp
passwd          passwd.copy     vi.recover
# rm /var/tmp/passwd*
# ls /var/tmp
vi.recover

此时,用户注意到删除了额外的文件并希望将其恢复。当定期对重要数据进行快照时,ZFS 提供了一种使用回滚轻松将其恢复的方法。要恢复文件并从最后一个快照开始重新开始,请执行以下命令

# zfs rollback mypool/var/tmp@diff_snapshot
# ls /var/tmp
passwd          passwd.copy     vi.recover

回滚操作将数据集恢复到最后一个快照的状态。也可以回滚到早些时候拍摄的快照,而之后拍摄的其他快照仍然存在。尝试执行此操作时,ZFS 会发出以下警告

# zfs list -rt snapshot mypool/var/tmp
AME                                   USED  AVAIL  REFER  MOUNTPOINT
mypool/var/tmp@my_recursive_snapshot    88K      -   152K  -
mypool/var/tmp@after_cp               53.5K      -   118K  -
mypool/var/tmp@diff_snapshot              0      -   120K  -
# zfs rollback mypool/var/tmp@my_recursive_snapshot
cannot rollback to 'mypool/var/tmp@my_recursive_snapshot': more recent snapshots exist
use '-r' to force deletion of the following snapshots:
mypool/var/tmp@after_cp
mypool/var/tmp@diff_snapshot

此警告表示数据集的当前状态与用户想要回滚到的快照之间存在快照。要完成回滚,请删除这些快照。ZFS 无法跟踪数据集不同状态之间的所有更改,因为快照是只读的。除非用户指定 -r 以确认这是所需操作,否则 ZFS 不会删除受影响的快照。如果这是您的意图,并且了解丢失所有中间快照的后果,请执行以下命令

# zfs rollback -r mypool/var/tmp@my_recursive_snapshot
# zfs list -rt snapshot mypool/var/tmp
NAME                                   USED  AVAIL  REFER  MOUNTPOINT
mypool/var/tmp@my_recursive_snapshot     8K      -   152K  -
# ls /var/tmp
vi.recover

zfs list -t snapshot 的输出确认由于 zfs rollback -r 而删除了中间快照。

22.4.5.4. 从快照恢复单个文件

快照位于父数据集下的隐藏目录中:.zfs/snapshots/snapshotname。默认情况下,即使执行标准 ls -a,这些目录也不会显示。尽管该目录未显示,但可以像任何普通目录一样访问它。名为 snapdir 的属性控制这些隐藏目录是否显示在目录列表中。将该属性设置为 visible 允许它们出现在 ls 和处理目录内容的其他命令的输出中。

# zfs get snapdir mypool/var/tmp
NAME            PROPERTY  VALUE    SOURCE
mypool/var/tmp  snapdir   hidden   default
# ls -a /var/tmp
.               ..              passwd          vi.recover
# zfs set snapdir=visible mypool/var/tmp
# ls -a /var/tmp
.               ..              .zfs            passwd          vi.recover

通过将文件从快照复制回父数据集来将单个文件恢复到以前的状态。.zfs/snapshot 下的目录结构包含一个与之前拍摄的快照同名的目录,以便更轻松地识别它们。以下示例显示了如何通过从包含文件的最新版本的快照中复制文件来从隐藏的 .zfs 目录中恢复文件

# rm /var/tmp/passwd
# ls -a /var/tmp
.               ..              .zfs            vi.recover
# ls /var/tmp/.zfs/snapshot
after_cp                my_recursive_snapshot
# ls /var/tmp/.zfs/snapshot/after_cp
passwd          vi.recover
# cp /var/tmp/.zfs/snapshot/after_cp/passwd /var/tmp

即使 snapdir 属性设置为隐藏,运行 ls .zfs/snapshot 仍然会列出该目录的内容。管理员决定是否显示这些目录。这是一个针对每个数据集的设置。从这个隐藏的 .zfs/snapshot 中复制文件或目录非常简单。尝试反过来会产生以下错误

# cp /etc/rc.conf /var/tmp/.zfs/snapshot/after_cp/
cp: /var/tmp/.zfs/snapshot/after_cp/rc.conf: Read-only file system

该错误提醒用户快照是只读的,并且创建后无法更改。不允许将文件复制到快照目录中或从其中删除文件,因为这会改变它们所代表的数据集的状态。

快照会根据自快照时间点以来父文件系统更改了多少而占用空间。快照的 written 属性会跟踪快照使用的空间。

要销毁快照并回收空间,请使用 zfs destroy dataset@snapshot。添加 -r 会递归地删除父数据集下具有相同名称的所有快照。将 -n -v 添加到命令中会显示要删除的快照列表以及回收的空间估算值,而不会执行实际的销毁操作。

22.4.6. 管理克隆

克隆是快照的副本,更像是一个常规数据集。与快照不同,克隆是可写的、可挂载的,并且具有自己的属性。使用 zfs clone 创建克隆后,无法销毁原始快照。要反转克隆与快照之间的子级/父级关系,请使用 zfs promote。提升克隆会使快照成为克隆的子级,而不是原始父数据集的子级。这会更改 ZFS 计算空间的方式,但不会实际更改所占用的空间量。可以将克隆挂载在 ZFS 文件系统层次结构中的任何位置,而不仅仅是在快照的原始位置下方。

要显示克隆功能,请使用以下示例数据集

# zfs list -rt all camino/home/joe
NAME                    USED  AVAIL  REFER  MOUNTPOINT
camino/home/joe         108K   1.3G    87K  /usr/home/joe
camino/home/joe@plans    21K      -  85.5K  -
camino/home/joe@backup    0K      -    87K  -

克隆的典型用途是对特定数据集进行实验,同时保留快照以便在出现问题时回滚。由于快照无法更改,因此请创建快照的读/写克隆。在克隆中获得所需的结果后,将克隆提升为数据集并删除旧文件系统。删除父数据集不是严格必要的,因为克隆和数据集可以共存而不会出现问题。

# zfs clone camino/home/joe@backup camino/home/joenew
# ls /usr/home/joe*
/usr/home/joe:
backup.txz     plans.txt

/usr/home/joenew:
backup.txz     plans.txt
# df -h /usr/home
Filesystem          Size    Used   Avail Capacity  Mounted on
usr/home/joe        1.3G     31k    1.3G     0%    /usr/home/joe
usr/home/joenew     1.3G     31k    1.3G     0%    /usr/home/joenew

创建克隆会使它成为拍摄快照时数据集状态的精确副本。现在可以独立于其原始数据集更改克隆。两者之间的连接是快照。ZFS 在 origin 属性中记录了这种连接。使用 zfs promote 提升克隆会使克隆成为独立的数据集。这将删除 origin 属性的值,并将新独立的数据集与快照断开连接。以下示例显示了这一点

# zfs get origin camino/home/joenew
NAME                  PROPERTY  VALUE                     SOURCE
camino/home/joenew    origin    camino/home/joe@backup    -
# zfs promote camino/home/joenew
# zfs get origin camino/home/joenew
NAME                  PROPERTY  VALUE   SOURCE
camino/home/joenew    origin    -       -

例如,在对提升的克隆进行一些更改(例如将 loader.conf 复制到提升的克隆)后,旧目录在这种情况下会变得过时。相反,提升的克隆可以替换它。为此,请首先使用 zfs destroy 销毁旧数据集,然后使用 zfs rename 将克隆重命名为旧数据集名称(或完全不同的名称)。

# cp /boot/defaults/loader.conf /usr/home/joenew
# zfs destroy -f camino/home/joe
# zfs rename camino/home/joenew camino/home/joe
# ls /usr/home/joe
backup.txz     loader.conf     plans.txt
# df -h /usr/home
Filesystem          Size    Used   Avail Capacity  Mounted on
usr/home/joe        1.3G    128k    1.3G     0%    /usr/home/joe

克隆的快照现在是一个普通的数据集。它包含了原始快照中的所有数据,以及添加的像loader.conf这样的文件。克隆在不同场景下为 ZFS 用户提供了一些有用的功能。例如,为 jail 提供快照,这些快照包含不同的已安装应用程序集。用户可以克隆这些快照,并根据需要添加自己的应用程序。一旦对更改感到满意,就可以将克隆提升为完整的数据集,并将其提供给最终用户使用,就像他们使用真实数据集一样。这在提供这些 jail 时节省了时间和管理开销。

22.4.7. 复制

将数据保留在一个位置的单个池中,会使它面临盗窃、自然灾害或人为灾害等风险。对整个池进行定期备份至关重要。ZFS 提供了一个内置的序列化功能,可以将数据的流表示发送到标准输出。使用此功能,可以将此数据存储在连接到本地系统的另一个池中,也可以将其通过网络发送到另一个系统。快照是此复制的基础(请参阅有关ZFS 快照的部分)。用于复制数据的命令是zfs sendzfs receive

以下示例展示了使用这两个池进行 ZFS 复制

# zpool list
NAME    SIZE  ALLOC   FREE   CKPOINT  EXPANDSZ   FRAG   CAP  DEDUP  HEALTH  ALTROOT
backup  960M    77K   896M         -         -     0%    0%  1.00x  ONLINE  -
mypool  984M  43.7M   940M         -         -     0%    4%  1.00x  ONLINE  -

名为mypool的池是主池,在该池中定期进行数据写入和读取。使用第二个备用池backup,以防主池不可用。请注意,此故障转移不是由 ZFS 自动完成的,而是在需要时必须由系统管理员手动完成。使用快照提供要复制的一致文件系统版本。创建mypool的快照后,通过复制快照将其复制到backup池。这并不包括自最近一次快照以来所做的更改。

# zfs snapshot mypool@backup1
# zfs list -t snapshot
NAME                    USED  AVAIL  REFER  MOUNTPOINT
mypool@backup1             0      -  43.6M  -

现在已存在快照,使用zfs send创建表示快照内容的流。将此流存储为文件或接收它到另一个池中。将流写入标准输出,但重定向到文件或管道,否则会出现错误

# zfs send mypool@backup1
Error: Stream can not be written to a terminal.
You must redirect standard output.

要使用zfs send备份数据集,请重定向到位于已挂载的备份池上的文件。确保池有足够的可用空间来容纳已发送快照的大小,这意味着快照中包含的数据,而不是自上次快照以来的更改。

# zfs send mypool@backup1 > /backup/backup1
# zpool list
NAME    SIZE  ALLOC   FREE   CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT
backup  960M  63.7M   896M         -         -     0%     6%  1.00x  ONLINE  -
mypool  984M  43.7M   940M         -         -     0%     4%  1.00x  ONLINE  -

zfs send将名为backup1的快照中的所有数据传输到名为backup的池中。要自动创建和发送这些快照,请使用cron(8)作业。

ZFS 可以将备份作为实时文件系统接收,而不是将其存储为存档文件,从而允许直接访问已备份的数据。要访问这些流中包含的实际数据,请使用zfs receive将流转换回文件和目录。以下示例结合了zfs sendzfs receive,使用管道将数据从一个池复制到另一个池。传输完成后,可以直接在接收池上使用数据。只能将数据集复制到空数据集。

# zfs snapshot mypool@replica1
# zfs send -v mypool@replica1 | zfs receive backup/mypool
send from @ to mypool@replica1 estimated size is 50.1M
total estimated size is 50.1M
TIME        SENT   SNAPSHOT

# zpool list
NAME    SIZE  ALLOC   FREE   CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT
backup  960M  63.7M   896M         -         -     0%     6%  1.00x  ONLINE  -
mypool  984M  43.7M   940M         -         -     0%     4%  1.00x  ONLINE  -

22.4.7.1. 增量备份

zfs send还可以确定两个快照之间的差异,并发送两个快照之间的个别差异。这节省了磁盘空间和传输时间。例如

# zfs snapshot mypool@replica2
# zfs list -t snapshot
NAME                    USED  AVAIL  REFER  MOUNTPOINT
mypool@replica1         5.72M      -  43.6M  -
mypool@replica2             0      -  44.1M  -
# zpool list
NAME    SIZE  ALLOC   FREE   CKPOINT  EXPANDSZ   FRAG   CAP  DEDUP  HEALTH  ALTROOT
backup  960M  61.7M   898M         -         -     0%    6%  1.00x  ONLINE  -
mypool  960M  50.2M   910M         -         -     0%    5%  1.00x  ONLINE  -

创建第二个名为replica2的快照。此第二个快照包含自现在到先前快照replica1之间对文件系统所做的更改。使用zfs send -i并指示一对快照,将生成一个增量副本流,其中包含已更改的数据。如果初始快照已存在于接收端,则此操作将成功。

# zfs send -v -i mypool@replica1 mypool@replica2 | zfs receive /backup/mypool
send from @replica1 to mypool@replica2 estimated size is 5.02M
total estimated size is 5.02M
TIME        SENT   SNAPSHOT

# zpool list
NAME    SIZE  ALLOC   FREE   CKPOINT  EXPANDSZ   FRAG  CAP  DEDUP  HEALTH  ALTROOT
backup  960M  80.8M   879M         -         -     0%   8%  1.00x  ONLINE  -
mypool  960M  50.2M   910M         -         -     0%   5%  1.00x  ONLINE  -

# zfs list
NAME                         USED  AVAIL  REFER  MOUNTPOINT
backup                      55.4M   240G   152K  /backup
backup/mypool               55.3M   240G  55.2M  /backup/mypool
mypool                      55.6M  11.6G  55.0M  /mypool

# zfs list -t snapshot
NAME                                         USED  AVAIL  REFER  MOUNTPOINT
backup/mypool@replica1                       104K      -  50.2M  -
backup/mypool@replica2                          0      -  55.2M  -
mypool@replica1                             29.9K      -  50.0M  -
mypool@replica2                                 0      -  55.0M  -

增量流复制了已更改的数据,而不是replica1的全部数据。仅发送差异,传输时间大大减少,并且通过不每次都复制整个池来节省磁盘空间。这在通过缓慢的网络或对每个传输字节收费的网络进行复制时非常有用。

现在,可以使用来自池mypool的文件和数据,可以使用一个新的文件系统backup/mypool。指定-p将复制数据集属性,包括压缩设置、配额和挂载点。指定-R将复制数据集的所有子数据集及其属性。自动执行发送和接收操作,以在第二个池上创建定期备份。

22.4.7.2. 通过 SSH 发送加密的备份

通过网络发送流是保存远程备份的好方法,但它也有一些缺点。通过网络链路发送的数据未加密,允许任何人拦截并将其转换回数据,而无需发送用户的知情。当通过互联网将流发送到远程主机时,这是不可取的。使用 SSH 安全地加密通过网络连接发送的数据。由于 ZFS 需要将流从标准输出重定向,因此通过 SSH 传递它很容易。要保持文件系统内容在传输中和远程系统上的加密状态,请考虑使用PEFS.

首先更改一些设置并采取安全预防措施。这描述了zfs send操作所需的必要步骤;有关 SSH 的更多信息,请参阅OpenSSH.

按如下所示更改配置

  • 使用 SSH 密钥在发送主机和接收主机之间进行无密码 SSH 访问

  • ZFS 需要root用户的权限才能发送和接收流。这要求以root身份登录到接收系统。

  • 出于安全原因,默认情况下不允许root登录。

  • 使用ZFS 委托系统允许每个系统上的非root用户执行相应的发送和接收操作。在发送系统上

    # zfs allow -u someuser send,snapshot mypool
  • 要挂载池,非特权用户必须拥有目录,并且普通用户需要挂载文件系统的权限。

在接收系统上

+

# sysctl vfs.usermount=1
vfs.usermount: 0 -> 1
# echo vfs.usermount=1 >> /etc/sysctl.conf
# zfs create recvpool/backup
# zfs allow -u someuser create,mount,receive recvpool/backup
# chown someuser /recvpool/backup

现在,非特权用户可以接收和挂载数据集,并将home数据集复制到远程系统

% zfs snapshot -r mypool/home@monday
% zfs send -R mypool/home@monday | ssh someuser@backuphost zfs recv -dvu recvpool/backup

在池mypool上创建文件系统数据集home的递归快照,名为monday。然后,zfs send -R将包含数据集、所有子数据集、快照、克隆和设置在流中。通过 SSH 将输出传递到远程主机backuphost上正在等待的zfs receive。使用 IP 地址或完全限定域名是一个好习惯。接收机将数据写入recvpool池上的backup数据集。在zfs recv中添加-d将使用快照的名称覆盖接收端的池名称。-u会导致文件系统在接收端不挂载。使用-v将显示有关传输的更多详细信息,包括经过的时间和传输的数据量。

22.4.8. 数据集、用户和组配额

使用数据集配额来限制特定数据集所使用的空间量。 参考配额的工作方式几乎相同,但它计算数据集本身使用的空间,不包括快照和子数据集。类似地,使用用户配额来阻止用户或组使用池或数据集中所有空间。

以下示例假设用户已存在于系统中。在将用户添加到系统之前,请确保首先创建他们的主目录数据集,并将mountpoint设置为/home/bob。然后,创建用户,并使主目录指向数据集的mountpoint位置。这将正确设置所有者和组权限,而不会覆盖可能存在的任何预先存在的 home 目录路径。

要对storage/home/bob实施 10 GB 的数据集配额,请使用

# zfs set quota=10G storage/home/bob

要对storage/home/bob实施 10 GB 的参考配额,请使用

# zfs set refquota=10G storage/home/bob

要删除storage/home/bob的 10 GB 配额,请使用

# zfs set quota=none storage/home/bob

一般格式是userquota@user=size,用户名称必须采用以下格式之一

  • 与 POSIX 兼容的名称,例如joe

  • POSIX 数字 ID,例如789

  • SID 名称,例如[email protected]

  • SID 数字 ID,例如S-1-123-456-789

例如,要对名为joe的用户实施 50 GB 的用户配额,请使用

# zfs set userquota@joe=50G

要删除任何配额,请使用

# zfs set userquota@joe=none

zfs get all不会显示用户配额属性。非root用户无法看到其他用户的配额,除非授予他们userquota权限。拥有此权限的用户能够查看和设置所有用户的配额。

设置组配额的一般格式为:groupquota@group=size

要将firstgroup组的配额设置为 50 GB,请使用

# zfs set groupquota@firstgroup=50G

要删除firstgroup组的配额,或确保未设置配额,请改用

# zfs set groupquota@firstgroup=none

与用户配额属性一样,非root用户可以查看与他们所属组关联的配额。拥有groupquota权限或root权限的用户可以查看和设置所有组的所有配额。

要显示每个用户在文件系统或快照上使用的空间量以及任何配额,请使用zfs userspace。要获取组信息,请使用zfs groupspace。有关支持选项或如何单独显示特定选项的更多信息,请参阅zfs(1).

特权用户和root可以使用以下命令列出storage/home/bob的配额

# zfs get quota storage/home/bob

22.4.9. 预留

预留保证数据集始终可用一定量的空间。保留的空间将不可用于任何其他数据集。此有用功能可确保为重要的数据集或日志文件提供可用空间。

reservation属性的一般格式为reservation=size,因此要对storage/home/bob设置 10 GB 的预留空间,请使用

# zfs set reservation=10G storage/home/bob

要清除任何预留空间,请使用

# zfs set reservation=none storage/home/bob

相同的原则适用于为设置参考预留refreservation属性,其一般格式为refreservation=size

此命令将显示storage/home/bob上存在的任何预留空间或参考预留空间

# zfs get reservation storage/home/bob
# zfs get refreservation storage/home/bob

22.4.10. 压缩

ZFS 提供透明压缩。在块级别压缩写入的数据可以节省空间,还可以提高磁盘吞吐量。如果数据压缩了 25%,则压缩后的数据写入磁盘的速度与未压缩版本相同,从而导致有效的写入速度为 125%。压缩也可以是重复数据删除的绝佳替代方案,因为它不需要额外的内存。

ZFS 提供不同的压缩算法,每种算法都有不同的权衡。ZFS v5000 中引入的 LZ4 压缩允许在不影响其他算法的巨大性能权衡的情况下压缩整个池。LZ4 的最大优势在于早期中止功能。如果 LZ4 在数据的标题部分中未达到至少 12.5% 的压缩率,则 ZFS 将写入未压缩的块,以避免浪费 CPU 周期来尝试压缩已压缩或不可压缩的数据。有关 ZFS 中提供的不同压缩算法的详细信息,请参阅术语部分中的压缩条目。

管理员可以使用数据集属性查看压缩的有效性。

# zfs get used,compressratio,compression,logicalused mypool/compressed_dataset
NAME        PROPERTY          VALUE     SOURCE
mypool/compressed_dataset  used              449G      -
mypool/compressed_dataset  compressratio     1.11x     -
mypool/compressed_dataset  compression       lz4       local
mypool/compressed_dataset  logicalused       496G      -

该数据集使用了 449 GB 的空间(used 属性)。如果没有压缩,它将占用 496 GB 的空间(logicalused 属性)。这会导致 1.11:1 的压缩率。

压缩与用户配额结合使用时,可能会产生意想不到的副作用。用户配额限制用户在数据集上压缩后实际占用的空间。如果用户配额为 10 GB,并且写入 10 GB 可压缩数据,他们仍然可以存储更多数据。如果他们后来更新文件(例如数据库),使用更多或更少可压缩数据,则他们可用的空间量将发生变化。这会导致一种奇怪的情况,即用户没有增加实际数据量(logicalused 属性),但压缩的变化导致他们达到配额限制。

压缩可能与备份产生类似的意想不到的交互。配额通常用于限制数据存储,以确保有足够的备份空间可用。由于配额不考虑压缩,因此 ZFS 可能会写入比未压缩备份所能容纳的更多数据。

22.4.11. Zstandard 压缩

OpenZFS 2.0 添加了一种新的压缩算法。Zstandard (Zstd) 提供比默认的 LZ4 更高的压缩率,同时提供比替代方案 gzip 快得多的速度。OpenZFS 2.0 从 FreeBSD 12.1-RELEASE 开始通过 sysutils/openzfs 提供,并且从 FreeBSD 13.0-RELEASE 开始成为默认值。

Zstd 提供了大量的压缩级别选择,可以对性能与压缩率进行细粒度控制。Zstd 的主要优势之一是解压缩速度与压缩级别无关。对于只写一次但经常读取的数据,Zstd 允许使用最高压缩级别,而不会影响读取性能。

即使数据频繁更新,启用压缩也通常能提高性能。最大的优势之一来自压缩的 ARC 功能。ZFS 的自适应替换缓存 (ARC) 将数据的压缩版本缓存在 RAM 中,每次解压缩它。这使得相同数量的 RAM 可以存储更多数据和元数据,从而提高缓存命中率。

ZFS 提供了 19 个级别的 Zstd 压缩,每个级别都以更慢的压缩速度换取更小的空间节省。默认级别为 zstd-3,它提供了比 LZ4 更大的压缩率,而不会慢很多。高于 10 的级别需要大量的内存来压缩每个块,内存小于 16 GB 的系统不应该使用它们。ZFS 还使用了一些 Zstd_fast_ 级别,这些级别相应地更快,但支持的压缩率更低。ZFS 支持 zstd-fast-1zstd-fast-10zstd-fast-20zstd-fast-100(以 10 为增量),以及 zstd-fast-500zstd-fast-1000,它们提供了最小的压缩,但提供了高性能。

如果 ZFS 无法获得使用 Zstd 压缩块所需的内存,它将回退到未压缩存储块。这种情况不太可能发生,除非在内存受限的系统上使用最高级别的 Zstd。ZFS 使用 kstat.zfs.misc.zstd.compress_alloc_fail 统计自加载 ZFS 模块以来发生这种情况的次数。

22.4.12. 重复数据消除

启用后,重复数据消除 使用每个块的校验和来检测重复块。当新块与现有块重复时,ZFS 会写入对现有数据的新的引用,而不是整个重复块。如果数据包含大量重复文件或重复信息,则可以实现巨大的空间节省。警告:重复数据消除需要大量的内存,而启用压缩则可以在没有额外成本的情况下提供大多数空间节省。

要激活重复数据消除,请在目标池上设置 dedup 属性

# zfs set dedup=on pool

重复数据消除只影响写入池的新数据。仅仅激活此选项不会对已写入池的数据进行重复数据消除。具有新激活的重复数据消除属性的池将类似于以下示例

# zpool list
NAME  SIZE ALLOC  FREE   CKPOINT  EXPANDSZ   FRAG   CAP   DEDUP   HEALTH   ALTROOT
pool 2.84G 2.19M 2.83G         -         -     0%    0%   1.00x   ONLINE   -

DEDUP 列显示池的实际重复数据消除率。值为 1.00x 表示数据尚未重复数据消除。以下示例将一些系统二进制文件复制三次到上面创建的重复数据消除池上的不同目录中。

# for d in dir1 dir2 dir3; do
> mkdir $d && cp -R /usr/bin $d &
> done

要观察冗余数据的重复数据消除,请使用

# zpool list
NAME SIZE  ALLOC  FREE   CKPOINT  EXPANDSZ   FRAG  CAP   DEDUP   HEALTH   ALTROOT
pool 2.84G 20.9M 2.82G         -         -     0%   0%   3.00x   ONLINE   -

DEDUP 列显示一个因子 3.00x。检测和重复数据消除数据的副本使用三分之一的空间。空间节省的潜力可能是巨大的,但需要有足够的内存来跟踪重复数据消除的块。

当池中的数据没有冗余时,重复数据消除并不总是有效的。ZFS 可以通过模拟现有池的重复数据消除来显示潜在的空间节省

# zdb -S pool
Simulated DDT histogram:

bucket              allocated                       referenced
______   ______________________________   ______________________________
refcnt   blocks   LSIZE   PSIZE   DSIZE   blocks   LSIZE   PSIZE   DSIZE
------   ------   -----   -----   -----   ------   -----   -----   -----
     1    2.58M    289G    264G    264G    2.58M    289G    264G    264G
     2     206K   12.6G   10.4G   10.4G     430K   26.4G   21.6G   21.6G
     4    37.6K    692M    276M    276M     170K   3.04G   1.26G   1.26G
     8    2.18K   45.2M   19.4M   19.4M    20.0K    425M    176M    176M
    16      174   2.83M   1.20M   1.20M    3.33K   48.4M   20.4M   20.4M
    32       40   2.17M    222K    222K    1.70K   97.2M   9.91M   9.91M
    64        9     56K   10.5K   10.5K      865   4.96M    948K    948K
   128        2   9.50K      2K      2K      419   2.11M    438K    438K
   256        5   61.5K     12K     12K    1.90K   23.0M   4.47M   4.47M
    1K        2      1K      1K      1K    2.98K   1.49M   1.49M   1.49M
 Total    2.82M    303G    275G    275G    3.20M    319G    287G    287G

dedup = 1.05, compress = 1.11, copies = 1.00, dedup * compress / copies = 1.16

zdb -S 完成对池的分析后,它会显示激活重复数据消除将实现的空间缩减率。在本例中,1.16 是一个较差的空间节省率,主要由压缩提供。在该池上激活重复数据消除不会节省任何空间,并且不值得启用重复数据消除所需的内存量。使用公式比率 = 重复数据消除 * 压缩 / 副本,系统管理员可以规划存储分配,决定工作负载是否包含足够的重复块来证明内存需求。如果数据是合理的压缩,则空间节省可能是好的。最佳做法是首先启用压缩,因为压缩也提供了更高的性能。在节省显著且有足够的可用内存来使用 DDT 的情况下启用重复数据消除。

22.4.13. ZFS 和 Jail

使用 zfs jail 和相应的 jailed 属性将 ZFS 数据集委托给 Jailzfs jail jailid 将数据集附加到指定的 Jail,zfs unjail 将其分离。要从 Jail 中控制数据集,请设置 jailed 属性。ZFS 禁止将 Jail 数据集安装到主机,因为它可能具有会损害主机安全性的挂载点。

22.5. 委托管理

一个全面的权限委托系统允许非特权用户执行 ZFS 管理功能。例如,如果每个用户的 home 目录都是一个数据集,那么用户需要有权限创建和销毁其 home 目录的快照。执行备份的用户可以获得使用复制功能的权限。ZFS 允许使用统计脚本运行,该脚本仅访问所有用户的空间使用数据。还可能委托委托权限的能力。权限委托对于每个子命令和大多数属性都是可能的。

22.5.1. 委托数据集创建

zfs allow someuser create mydataset 允许指定的用户在选定的父数据集下创建子数据集。一个警告:创建新的数据集涉及挂载它。这需要设置 FreeBSD vfs.usermount sysctl(8)1,以允许非 root 用户挂载文件系统。另一个旨在防止滥用的限制:非 root 用户必须拥有挂载文件系统的挂载点。

22.5.2. 委托权限委托

zfs allow someuser allow mydataset 允许指定的用户将他们对目标数据集或其子数据集的任何权限分配给其他用户。如果用户拥有 snapshot 权限和 allow 权限,那么该用户就可以将 snapshot 权限授予其他用户。

22.6. 高级主题

22.6.1. 调整

调整可调参数,使 ZFS 对不同的工作负载表现最佳。

  • vfs.zfs.arc.max 从 13.x 开始(对于 12.x,为 vfs.zfs.arc_max)- ARC 的上限。默认值为所有 RAM 减去 1 GB 或所有 RAM 的 5/8,取较大者。如果系统运行任何其他守护程序或进程可能需要内存,则使用较低的值。使用 sysctl(8) 在运行时调整此值,并在 /boot/loader.conf/etc/sysctl.conf 中设置。

  • vfs.zfs.arc.meta_limit 从 13.x 开始(对于 12.x,为 vfs.zfs.arc_meta_limit)- 限制用于存储元数据的 ARC 的大小。默认值为 vfs.zfs.arc.max 的四分之一。如果工作负载涉及对大量文件和目录的操作,或频繁的元数据操作,则增加此值将提高性能,但代价是 ARC 中可以容纳更少的文件数据。使用 sysctl(8) 在运行时调整此值,并在 /boot/loader.conf/etc/sysctl.conf 中设置。

  • vfs.zfs.arc.min 从 13.x 开始(对于 12.x,为 vfs.zfs.arc_min)- ARC 的下限。默认值为 vfs.zfs.arc.meta_limit 的一半。调整此值以防止其他应用程序将整个 ARC 压出。使用 sysctl(8) 在运行时调整此值,并在 /boot/loader.conf/etc/sysctl.conf 中设置。

  • vfs.zfs.vdev.cache.size- 为池中的每个设备预先分配的内存量,作为缓存保留。使用的内存总量将是此值乘以设备数量。在启动时设置此值,并在 /boot/loader.conf 中设置。

  • vfs.zfs.min_auto_ashift- 在池创建时自动使用的较低的 ashift(扇区大小)。该值是 2 的幂。默认值为 9 表示 2^9 = 512,扇区大小为 512 字节。为了避免写放大并获得最佳性能,请将此值设置为池中设备使用的最大扇区大小。

    常见的硬盘拥有 4 KB 的扇区。在这些硬盘上使用默认的 ashift9 会导致写入放大。单个 4 KB 写入的数据将被写入到八个 512 字节的写入中。ZFS 在创建存储池时会尝试从所有设备读取本机扇区大小,但是具有 4 KB 扇区的硬盘会为了兼容性而报告其扇区为 512 字节。在创建存储池之前将 vfs.zfs.min_auto_ashift 设置为 12 (2^12 = 4096) 可以强制 ZFS 使用 4 KB 块,从而在这些硬盘上获得最佳性能。

    强制使用 4 KB 块对于具有计划磁盘升级的存储池也很有用。未来的磁盘将使用 4 KB 扇区,而 ashift 值在创建存储池后无法更改。

    在某些特定情况下,较小的 512 字节块大小可能更可取。当与 512 字节磁盘一起用于数据库或作为虚拟机的存储时,在小型随机读取期间的数据传输量更少。这在使用较小的 ZFS 记录大小时可以提供更好的性能。

  • vfs.zfs.prefetch_disable - 禁用预取。值为 0 表示启用,1 表示禁用。默认值为 0,除非系统内存小于 4 GB。预取通过将比请求更大的块读入 ARC 来工作,希望很快就会需要这些数据。如果工作负载包含大量随机读取,禁用预取实际上可以通过减少不必要的读取来提高性能。随时使用 sysctl(8) 调整此值。

  • vfs.zfs.vdev.trim_on_init - 控制是否在新设备添加到存储池后对其运行 TRIM 命令。这可以确保 SSD 的最佳性能和使用寿命,但需要额外的时间。如果设备已经安全擦除,禁用此设置将使新设备的添加更快。随时使用 sysctl(8) 调整此值。

  • vfs.zfs.vdev.max_pending - 限制每个设备的挂起 I/O 请求数量。较高的值将使设备命令队列保持满负荷状态,并可能提供更高的吞吐量。较低的值将减少延迟。随时使用 sysctl(8) 调整此值。

  • vfs.zfs.top_maxinflight - 每个顶级 vdev 的最大未完成 I/O 数量。限制命令队列的深度以防止高延迟。限制是针对每个顶级 vdev 的,这意味着限制适用于每个 镜像RAID-Z 或其他 vdev,独立生效。随时使用 sysctl(8) 调整此值。

  • vfs.zfs.l2arc_write_max - 限制每秒写入 L2ARC 的数据量。此可调参数通过限制写入设备的数据量来延长 SSD 的使用寿命。随时使用 sysctl(8) 调整此值。

  • vfs.zfs.l2arc_write_boost - 将此可调参数的值添加到 vfs.zfs.l2arc_write_max 中,并提高写入 SSD 的速度,直到从 L2ARC 中驱逐第一个块。此“Turbo 预热阶段”减少了从重新启动后空的 L2ARC 中产生的性能损失。随时使用 sysctl(8) 调整此值。

  • vfs.zfs.scrub_delay - 在 scrub 期间每次 I/O 之间延迟的刻度数。为了确保 scrub 不会干扰存储池的正常运行,如果有任何其他 I/O 正在进行,scrub 将在每个命令之间延迟。此值控制 scrub 生成的总 IOPS (每秒 I/O 次数) 限制。设置的粒度由 kern.hz 的值决定,该值默认设置为每秒 1000 个刻度。更改此设置会导致不同的有效 IOPS 限制。默认值为 4,导致限制为:1000 个刻度/秒 / 4 = 250 个 IOPS。使用 20 的值将导致限制为:1000 个刻度/秒 / 20 = 50 个 IOPS。存储池上的最新活动限制了 scrub 的速度,如 vfs.zfs.scan_idle 所决定。随时使用 sysctl(8) 调整此值。

  • vfs.zfs.resilver_delay - 在 resilver 期间每次 I/O 之间插入的延迟毫秒数。为了确保 resilver 不会干扰存储池的正常运行,如果有任何其他 I/O 正在进行,resilver 将在每个命令之间延迟。此值控制 resilver 生成的总 IOPS (每秒 I/O 次数) 限制。ZFS 通过 kern.hz 的值来确定设置的粒度,该值默认设置为每秒 1000 个刻度。更改此设置会导致不同的有效 IOPS 限制。默认值为 2,导致限制为:1000 个刻度/秒 / 2 = 500 个 IOPS。如果另一个设备出现故障可能会导致存储池 故障,从而导致数据丢失,那么将存储池恢复到 在线 状态可能更为重要。值为 0 将使 resilver 操作与其他操作具有相同的优先级,从而加快修复过程。存储池上的其他最新活动限制了 resilver 的速度,如 vfs.zfs.scan_idle 所决定。随时使用 sysctl(8) 调整此值。

  • vfs.zfs.scan_idle - 自上次操作以来经过的毫秒数,在该时间后将存储池视为处于空闲状态。当存储池处于空闲状态时,ZFS 会禁用 scrubresilver 的速率限制。随时使用 sysctl(8) 调整此值。

  • vfs.zfs.txg.timeout - 事务组 之间的最大秒数。当前事务组写入存储池,如果自上次事务组以来已过此时间量,则将开始新的事务组。如果写入足够多的数据,事务组可能会提前触发。默认值为 5 秒。较大的值可能会通过延迟异步写入来提高读取性能,但这可能会导致在写入事务组时性能不均匀。随时使用 sysctl(8) 调整此值。

22.6.2. i386 上的 ZFS

ZFS 提供的一些功能会占用大量内存,并且可能需要针对内存有限的系统进行调整才能获得更高的效率。

22.6.2.1. 内存

作为较低的值,系统总内存应至少为 1 GB。推荐的 RAM 量取决于存储池的大小以及 ZFS 使用的功能。一个经验法则是每 1 TB 存储空间使用 1 GB RAM。如果使用去重功能,一个经验法则是每 TB 存储空间使用 5 GB RAM 进行去重。虽然有些用户使用 ZFS 时内存更少,但在负载较大的情况下,系统可能会因内存耗尽而崩溃。对于内存低于推荐要求的系统,ZFS 可能需要进一步调整。

22.6.2.2. 内核配置

由于 i386™ 平台的地址空间限制,i386™ 架构上的 ZFS 用户必须将此选项添加到自定义内核配置文件中,重新构建内核并重启

options        KVA_PAGES=512

这将扩展内核地址空间,允许 vm.kvm_size 可调参数超过 1 GB 的限制,或者 PAE 的 2 GB 限制。要查找此选项的最合适值,请将所需的地址空间(以兆字节为单位)除以 4。在本例中,2 GB 为 512

22.6.2.3. 加载程序可调参数

在所有 FreeBSD 架构上增加 kmem 地址空间。具有 1 GB 物理内存的测试系统可以通过将这些选项添加到 /boot/loader.conf 中,然后重新启动来获益

vm.kmem_size="330M"
vm.kmem_size_max="330M"
vfs.zfs.arc.max="40M"
vfs.zfs.vdev.cache.size="5M"

有关与 ZFS 相关的调优推荐的更详细列表,请参阅 https://wiki.freebsd.org/ZFSTuningGuide.

22.8. ZFS 功能和术语

ZFS 不仅仅是一个文件系统,它在根本上有所不同。ZFS 将文件系统和卷管理器的角色结合起来,使新的存储设备能够添加到实时系统中,并使新的空间立即在该存储池中的现有文件系统上可用。通过将传统上独立的角色结合在一起,ZFS 能够克服以前限制 RAID 组扩展的限制。vdev 是存储池中的顶级设备,可以是简单的磁盘,也可以是 RAID 变换,例如镜像或 RAID-Z 阵列。ZFS 文件系统(称为 数据集)都可以访问整个存储池的可用空间。存储池中已使用的块会减少每个文件系统可用的空间。这种方法避免了在广泛分区中常见的陷阱,即可用空间在分区之间变得碎片化。

存储池

存储 是 ZFS 最基本的构建块。存储池包含一个或多个 vdev,即存储数据的底层设备。然后使用存储池来创建一个或多个文件系统(数据集)或块设备(卷)。这些数据集和卷共享剩余可用空间的存储池。每个存储池都由名称和 GUID 唯一标识。存储池上的 ZFS 版本号决定了可用的功能。

vdev 类型

存储池包含一个或多个 vdev,vdev 本身是单个磁盘或磁盘组,经过 RAID 变换。当使用大量 vdev 时,ZFS 会将数据分散到 vdev 中以提高性能并最大限度地利用可用空间。所有 vdev 的大小都必须至少为 128 MB。

  • 磁盘 - 最基本的 vdev 类型是标准块设备。这可以是整个磁盘(例如 /dev/ada0/dev/da0)或分区(/dev/ada0p3)。在 FreeBSD 上,使用分区与使用整个磁盘相比,没有性能上的损失。这与 Solaris 文档中提出的建议不同。

    强烈建议不要将整个磁盘用作可启动存储池的一部分,因为这可能会导致存储池无法启动。同样,也不应将整个磁盘用作镜像或 RAID-Z vdev 的一部分。在启动时可靠地确定未分区磁盘的大小是不可能的,并且没有地方可以放置启动代码。

  • 文件 - 普通文件可以构成 ZFS 池,这对于测试和实验很有用。在 zpool create 中使用文件的完整路径作为设备路径。

  • 镜像 - 创建镜像时,指定 mirror 关键字,后跟镜像的成员设备列表。镜像由两个或多个设备组成,将所有数据写入所有成员设备。镜像 vdev 将容纳与其最小成员一样多的数据。镜像 vdev 可以承受除一个成员之外的所有成员的故障,而不会丢失任何数据。

    要随时将普通单磁盘 vdev 升级到镜像 vdev,请使用 zpool attach

  • RAID-Z - ZFS 使用 RAID-Z,它是标准 RAID-5 的一种变体,它提供了更好的奇偶校验分布,并消除了“RAID-5 写入漏洞”,在该漏洞中,数据和奇偶校验信息在意外重启后变得不一致。ZFS 支持三种级别的 RAID-Z,它们以不同的冗余级别换取不断减少的可用存储级别。ZFS 根据阵列中的奇偶校验设备数量以及在池停止运行之前可以失败的磁盘数量,使用 RAID-Z1 到 RAID-Z3。

    在具有四个磁盘的 RAID-Z1 配置中,每个磁盘为 1 TB,可用存储空间为 3 TB,并且池仍然能够以降级模式运行,有一个磁盘发生故障。如果另一个磁盘在替换和重新同步故障磁盘之前脱机,将导致所有池数据丢失。

    在具有八个 1 TB 磁盘的 RAID-Z3 配置中,卷将提供 5 TB 的可用空间,并且仍然能够以三个磁盘发生故障的情况下运行。Sun™ 建议单个 vdev 中不超过九个磁盘。如果配置中包含更多磁盘,建议将它们划分为单独的 vdev,并在它们之间对池数据进行条带化。

    由两个 RAID-Z2 vdev 组成的配置,每个 vdev 包含 8 个磁盘,将创建类似于 RAID-60 阵列的东西。RAID-Z 组的存储容量约等于最小磁盘的大小乘以非奇偶校验磁盘的数量。四个 1 TB 磁盘在 RAID-Z1 中的有效大小约为 3 TB,八个 1 TB 磁盘在 RAID-Z3 中的阵列将产生 5 TB 的可用空间。

  • 备用 - ZFS 有一种特殊的伪 vdev 类型,用于跟踪可用的热备用。请注意,已安装的热备用不会自动部署;使用 zfs replace 手动配置它们以替换故障设备。

  • 日志 - ZFS 日志设备,也称为 ZFS 意图日志 (ZIL) 将意图日志从常规池设备移动到专用设备,通常是 SSD。拥有专用的日志设备可以提高具有大量同步写入(如数据库)的应用程序的性能。日志设备的镜像是可能的,但不支持 RAID-Z。如果使用大量日志设备,写入将在这其中进行负载均衡。

  • 缓存 - 向池中添加缓存 vdev 将将缓存的存储空间添加到 L2ARC 中。镜像缓存设备是不可能的。由于缓存设备仅存储现有数据的副本,因此没有数据丢失的风险。

事务组 (TXG)

事务组是 ZFS 将块更改分组在一起并将其写入池的方式。事务组是 ZFS 用于确保一致性的原子单位。ZFS 为每个事务组分配一个唯一的 64 位连续标识符。一次最多可以有三个活动事务组,每个组处于以下三种状态之一

* 打开 - 新事务组从打开状态开始,并接受新的写入。始终存在一个处于打开状态的事务组,但如果事务组已达到限制,它可能会拒绝新的写入。一旦打开的事务组已达到限制,或者达到 vfs.zfs.txg.timeout,事务组将前进到下一状态。 * 静默 - 一个短暂的状态,允许任何挂起的操作完成,而不会阻止创建新的打开的事务组。一旦该组中的所有事务都已完成,事务组将前进到最终状态。 * 同步 - 将事务组中的所有数据写入稳定存储。这个过程反过来会更改其他数据,例如元数据和空间映射,ZFS 也将将其写入稳定存储。同步过程涉及多个步骤。在第一个也是最大的步骤中,所有已更改的数据块;接下来是元数据,可能需要多个步骤才能完成。由于为数据块分配空间会生成新的元数据,因此同步状态在完成不使用任何新空间的步骤之前无法完成。同步状态也是同步任务完成的地方。同步任务是管理操作,例如创建或销毁快照和数据集,这些操作完成了超块更改。一旦同步状态完成,处于静默状态的事务组将前进到同步状态。所有管理功能,例如 snapshot 作为事务组的一部分写入。ZFS 将创建的同步任务添加到打开的事务组中,并且该组尽快前进到同步状态,以减少管理命令的延迟。

自适应替换缓存 (ARC)

ZFS 使用自适应替换缓存 (ARC),而不是更传统的最近最少使用 (LRU) 缓存。LRU 缓存是缓存中项目的简单列表,按项目最近使用的顺序排序,将新项目添加到列表的头部。当缓存已满时,从列表的尾部逐出项目,为更多活动对象腾出空间。ARC 包含四个列表;最近最少使用 (MRU) 和最常使用 (MFU) 对象,以及每个列表的幽灵列表。这些幽灵列表跟踪被逐出的对象,以防止将它们添加回缓存。通过避免偶尔使用过的对象,这可以提高缓存命中率。使用 MRU 和 MFU 的另一个优点是,扫描整个文件系统将逐出 MRU 或 LRU 缓存中的所有数据,以支持这些新访问的内容。在 ZFS 中,还有一个 MFU 跟踪最常使用过的对象,并且最常访问的块的缓存仍然存在。

L2ARC

L2ARC 是 ZFS 缓存系统的第二级。RAM 存储主要的 ARC。由于可用 RAM 的数量通常有限,ZFS 还可以使用 缓存 vdev。固态硬盘 (SSD) 通常用作这些缓存设备,因为与传统的旋转磁盘相比,它们具有更高的速度和更低的延迟。L2ARC 完全可选,但拥有它会提高缓存文件中在 SSD 上读取的速度,而不必从常规磁盘中读取。L2ARC 还可以加快 重复数据删除 的速度,因为不适合 RAM 但适合 L2ARC 的重复数据删除表 (DDT) 将比必须从磁盘读取的 DDT 快得多。添加到缓存设备的数据速率限制可以防止 SSD 因额外的写入而过早磨损。在缓存已满之前(逐出第一个块以腾出空间),写入 L2ARC 的限制为写入限制和提升限制的总和,之后限制为写入限制。一对 sysctl(8) 值控制这些速率限制。 vfs.zfs.l2arc_write_max 控制每秒写入缓存的字节数,而 vfs.zfs.l2arc_write_boost 在“涡轮增压预热阶段”(写入提升)期间增加了此限制。

ZIL

ZIL 通过使用比主存储池中使用的存储设备(如 SSD)速度更快的存储设备来加速同步事务。当应用程序请求同步写入(保证数据存储到磁盘而不是仅仅缓存以供以后写入)时,将数据写入速度更快的 ZIL 存储,然后将其刷新到常规磁盘,这大大减少了延迟并提高了性能。像数据库这样的同步工作负载将单独从 ZIL 中获益。常规的异步写入(例如复制文件)根本不会使用 ZIL。

写时复制

与传统的文件系统不同,ZFS 写入不同的块,而不是就地覆盖旧数据。在完成此写入后,元数据更新为指向新位置。当发生短写(在写入文件的过程中系统崩溃或电源丢失)时,文件的整个原始内容仍然可用,ZFS 会丢弃不完整的写入。这也意味着 ZFS 不需要 fsck(8) 在意外关机后。

数据集

数据集是 ZFS 文件系统、卷、快照或克隆的通用术语。每个数据集在 poolname/path@snapshot 格式中都有一个唯一的名称。池的根也是一个数据集。子数据集具有类似于目录的分层名称。例如,mypool/home(主数据集)是 mypool 的子级,并继承其属性。通过创建 mypool/home/user 进一步扩展它。这个孙子数据集将继承来自父级和祖父母的属性。在子级上设置属性以覆盖从父级和祖父母继承的默认值。数据集及其子级的管理可以 委派

文件系统

ZFS 数据集最常用作文件系统。与大多数其他文件系统一样,ZFS 文件系统安装在系统目录层次结构中的某个位置,并包含其自身具有权限、标志和其他元数据的文件和目录。

ZFS 还可以创建卷,这些卷显示为磁盘设备。卷具有与数据集相同的大量功能,包括写时复制、快照、克隆和校验和。卷对于在 ZFS 之上运行其他文件系统格式很有用,例如 UFS 虚拟化或导出 iSCSI 扩展。

快照

ZFS 的 写时复制 (COW) 设计允许以近乎瞬时的、一致的方式创建任意名称的快照。在对数据集进行快照(或对包含所有子数据集的父数据集进行递归快照)后,新数据将写入新块,但不会将旧块回收为可用空间。快照包含原始文件系统版本,而实时文件系统包含自创建快照以来进行的任何更改,而不会使用其他空间。写入实时文件系统的新的数据使用新的块来存储这些数据。当块不再在实时文件系统中使用,而仅在快照中使用时,快照会增长。以只读方式挂载这些快照允许恢复以前的文件版本。可以将实时文件系统 回滚 到特定快照,撤消自创建快照后发生的任何更改。池中的每个块都有一个引用计数器,它跟踪使用该块的快照、克隆、数据集或卷。随着文件和快照被删除,引用计数减少,当不再引用块时回收可用空间。用 保留 标记快照会导致任何尝试销毁它的操作都返回 EBUSY 错误。每个快照都可以具有具有唯一名称的保留。 释放 命令删除保留,以便可以删除快照。快照、克隆和回滚适用于卷,但独立挂载不适用于卷。

克隆

克隆快照也是可行的。克隆是快照的可写版本,允许文件系统作为新的数据集进行分叉。与快照一样,克隆最初不会占用任何新的空间。当写入克隆的新数据使用新的块时,克隆的大小会增加。当克隆的文件系统或卷中覆盖块时,先前块的引用计数会减少。无法删除克隆所基于的快照,因为克隆依赖于它。快照是父级,克隆是子级。克隆可以被*提升*,反转这种依赖关系,使克隆成为父级,而先前的父级成为子级。此操作不需要新的空间。由于父级和子级使用的空间量会反转,因此它可能会影响现有的配额和预留空间。

校验和

每个块也会进行校验和。使用的校验和算法是每个数据集的属性,请参见 set。每个块的校验和在读取时会透明地进行验证,允许 ZFS 检测静默损坏。如果读取的数据与预期的校验和不匹配,ZFS 将尝试从任何可用的冗余(如镜像或 RAID-Z)中恢复数据。使用 scrub 触发所有校验和的验证。校验和算法包括

* fletcher2 * fletcher4 * sha256 fletcher 算法速度更快,但 sha256 是一个强大的加密哈希,并且在一定性能损失的情况下,碰撞的可能性要低得多。停用校验和是可能的,但强烈建议不要这样做。

压缩

每个数据集都有一个压缩属性,默认情况下为关闭。将此属性设置为可用的压缩算法。这会导致写入数据集的所有新数据进行压缩。除了减少使用的空间之外,读写吞吐量通常也会增加,因为需要读取或写入的块更少。

* LZ4 - 在 ZFS 池版本 5000(功能标志)中添加,LZ4 现在是推荐的压缩算法。LZ4 在处理可压缩数据时比 LZJB 快约 50%,在处理不可压缩数据时快三倍以上。LZ4 的解压缩速度也比 LZJB 快约 80%。在现代 CPU 上,LZ4 的压缩速度通常可以超过 500 MB/s,解压缩速度可以超过 1.5 GB/s(每个 CPU 内核)。

* LZJB - 默认压缩算法。由 Jeff Bonwick(ZFS 的最初创建者之一)创建。与 GZIP 相比,LZJB 提供了良好的压缩,但 CPU 开销更低。将来,默认压缩算法将更改为 LZ4。

* GZIP - ZFS 中可用的流行流压缩算法。使用 GZIP 的主要优势之一是它的可配置压缩级别。在设置 compress 属性时,管理员可以选择压缩级别,从 gzip1(最低压缩级别)到 gzip9(最高压缩级别)。这使管理员能够控制为节省磁盘空间而牺牲多少 CPU 时间。

* ZLE - 零长度编码是一种特殊的压缩算法,仅压缩连续的零运行。当数据集包含大块零时,此压缩算法很有用。

副本

当设置为大于 1 的值时,copies 属性指示 ZFS 在 crossref:zfs[zfs-term-filesystem,文件系统] 或 中维护每个块的副本。在重要数据集上设置此属性可以提供额外的冗余,从中可以恢复与校验和不匹配的块。在没有冗余的池中,副本功能是唯一的冗余形式。副本功能可以从单个坏扇区或其他形式的轻微损坏中恢复,但它不能保护池免受整个磁盘丢失的影响。

重复数据删除

校验和使在写入数据时检测重复块成为可能。使用重复数据删除,现有相同块的引用计数会增加,从而节省存储空间。ZFS 在内存中保留一个重复数据删除表 (DDT) 来检测重复块。该表包含一个唯一校验和列表、这些块的位置以及引用计数。在写入新数据时,ZFS 会计算校验和并将它们与列表进行比较。当找到匹配项时,它会使用现有的块。将 SHA256 校验和算法与重复数据删除一起使用可提供安全的加密哈希。重复数据删除是可调的。如果 dedupon,则匹配的校验和表示数据相同。将 dedup 设置为 verify,ZFS 会对数据执行逐字节检查,确保它们实际上是相同的。如果数据不相同,ZFS 会记录哈希冲突并分别存储这两个块。由于 DDT 必须存储每个唯一块的哈希值,因此它会消耗大量内存。一般经验法则是每 1 TB 的重复数据删除数据使用 5-6 GB 的 RAM)。在没有足够的 RAM 来将整个 DDT 保留在内存中的情况下,性能会大大下降,因为 DDT 必须在写入每个新块之前从磁盘读取。重复数据删除可以使用 L2ARC 来存储 DDT,在快速系统内存和较慢的磁盘之间提供折衷方案。考虑使用压缩,它通常可以提供几乎相同的空间节省,而无需增加内存。

擦洗

ZFS 没有像 fsck(8) 这样的一致性检查,而是有 scrubscrub 读取存储在池上的所有数据块,并根据存储在元数据中的已知良好校验和验证它们的校验和。对存储在池上的所有数据的定期检查确保在需要之前恢复任何损坏的块。在不干净关机后不需要擦洗,但最佳实践是至少每三个月执行一次。ZFS 在正常使用期间会验证每个块的校验和,但擦洗可以确保即使是很少使用的块也会被检查以进行静默损坏。ZFS 提高了归档存储情况下的数据安全性。使用 vfs.zfs.scrub_delay 调整 scrub 的相对优先级,以防止擦洗降低池上其他工作负载的性能。

数据集配额

ZFS 提供快速准确的数据集、用户和组空间统计,以及配额和空间预留。这使管理员能够对空间分配进行精细控制,并允许为关键文件系统预留空间。

ZFS 支持不同类型的配额:数据集配额、引用配额 (refquota)用户配额组配额

配额限制了数据集及其后代的总大小,包括数据集的快照、子数据集以及这些数据集的快照。

卷不支持配额,因为 volsize 属性充当隐式配额。

引用配额

引用配额通过强制硬限制来限制数据集可以消耗的空间量。此硬限制包括仅数据集引用的空间,不包括后代(如文件系统或快照)使用的空间。

用户配额

用户配额对于限制指定用户使用的空间量很有用。

组配额

组配额限制了指定组可以消耗的空间量。

数据集预留

reservation 属性可以保证特定数据集及其后代使用一定的空间量。这意味着在 storage/home/bob 上设置 10 GB 的预留空间可以防止其他数据集使用所有可用空间,为该数据集预留至少 10 GB 的空间。与常规的 refreservation 不同,快照和后代使用的空间不会计入预留空间。例如,如果要对 storage/home/bob 进行快照,则除了 refreservation 空间量之外,还必须存在足够的磁盘空间才能使操作成功。主数据集的后代不会计入 refreservation 空间量,因此不会侵占已设置的空间。

任何类型的预留空间在以下情况下都很有用:例如,在新的系统中规划和测试磁盘空间分配的适用性,或确保文件系统上有足够的可用空间用于音频日志或系统恢复过程和文件。

引用预留

refreservation 属性可以保证特定数据集不包括其后代使用的空间量。这意味着在 storage/home/bob 上设置 10 GB 的预留空间,并且另一个数据集尝试使用可用空间,则会为该数据集预留至少 10 GB 的空间。与常规的 预留空间 不同,快照和后代数据集使用的空间不会计入预留空间。例如,如果要对 storage/home/bob 进行快照,则除了 refreservation 空间量之外,还必须存在足够的磁盘空间才能使操作成功。主数据集的后代不会计入 refreservation 空间量,因此不会侵占已设置的空间。

重新同步

在更换故障磁盘时,ZFS 必须使用丢失的数据填充新磁盘。*重新同步* 是使用分布在剩余驱动器上的奇偶校验信息来计算和写入丢失数据到新驱动器的过程。

联机

处于 联机 状态的池或 vdev 的成员设备已连接并正常运行。处于 联机 状态的单个设备正在运行。

脱机

如果存在足够的冗余以避免将池或 vdev 置于 故障 状态,管理员会将单个设备置于 脱机 状态。管理员可以选择在准备更换磁盘之前将其脱机,或者更容易识别它。

降级

处于 降级 状态的池或 vdev 存在一个或多个已消失或故障的磁盘。池仍然可以使用,但如果其他设备发生故障,池可能会变得无法恢复。重新连接丢失的设备或更换故障磁盘将在重新连接的设备或新设备完成 重新同步 过程后使池恢复到 联机 状态。

故障

处于`故障`状态的池或 vdev 已经停止运行。无法再访问数据。当丢失或故障设备的数量超过 vdev 中的冗余级别时,池或 vdev 会进入`故障`状态。如果重新连接丢失的设备,池将恢复到在线状态。如果冗余不足以弥补故障磁盘数量,池内容将丢失,需要从备份恢复。


最后修改时间: 2024 年 9 月 20 日,由 Fernando Apesteguía 修改