ZFS是一种高级文件系统,旨在解决以前存储子系统软件中发现的主要问题。
最初由Sun™开发,正在进行的开源ZFS开发已转移到OpenZFS项目。
ZFS有三个主要的设计目标:
数据完整性 —— Data integrity
所有数据都包含数据的校验和。ZFS计算校验和并将其与数据一起写入。稍后读取该数据时,ZFS会重新计算校验和。如果校验和不匹配,这意味着检测到一个或多个数据错误,ZFS将在有同上、镜像或奇偶校验块可用时尝试自动纠正错误。
池存储 —— Pooled storage
将物理存储设备添加到池中,并从该共享池中分配存储空间。空间可用于所有文件系统和卷,并通过向池中添加新的存储设备而增加。
性能 —— Performance
缓存机制提供了更高的性能。ARC是一种基于内存的高级读缓存。ZFS提供了一个具有L2ARC的二级基于磁盘的读缓存和一个名为ZIL的基于磁盘的同步写缓存。
【22.8. ZFS功能和术语】中提供了功能和术语的完整列表。
第二十二章 Z文件系统(ZFS)22.1. 是什么让ZFS与众不同22.2. 快速入门指南22.2.1. 单磁盘池22.2.2. RAID-Z22.2.3. 恢复RAID-Z22.2.4. 数据验证22.3. zpool 管理22.3.1. 创建和销毁存储池22.3.2. 添加和删除设备22.3.3. 检查池的状态22.3.4. 清除错误22.3.5. 更换功能正常的设备22.3.6. 处理故障设备22.3.7. 擦洗池22.3.8. 自愈22.3.9. 扩充池22.3.10. 导入和导出池22.3.11. 升级存储池22.3.12. 显示记录的池历史记录22.3.13. 性能监控22.3.14. 拆分存储池22.4. zfs 管理22.4.1. 创建和销毁数据集22.4.2. 创建和销毁卷22.4.3. 重命名数据集22.4.4. 设置数据集属性22.4.4.1. 获取和设置共享属性22.4.5. 管理快照22.4.5.1. 创建快照22.4.5.2. 比较快照22.4.5.3. 快照回滚22.4.5.4. 从快照还原单个文件22.4.6. 管理克隆22.4.7. 复制22.4.7.1. 增量备份22.4.7.2. 通过SSH发送加密备份22.4.8. 数据集、用户和组配额22.4.9. 预订22.4.10. 压缩22.4.11. Z标准压缩22.4.12. 去重22.4.13. ZFS和Jails22.5. 委托管理22.5.1. 委托数据集创建22.5.2. 委派权限委派22.6. 高级主题22.6.1. 调谐22.6.2. i386上的ZFS22.6.2.1. 内存22.6.2.2. 内核配置22.6.2.3. 装载机可调22.7. 更多资源22.8. ZFS特征和术语
ZFS不仅仅是一个文件系统,它与传统的文件系统有着根本的不同。将卷管理器和文件系统这两个传统上独立的角色结合起来,为ZFS提供了独特的优势。文件系统现在知道磁盘的底层结构。传统文件系统一次可以单独存在于单个磁盘上。如果有两个磁盘,则需要创建两个单独的文件系统。传统的硬件RAID配置通过向操作系统呈现由物理磁盘提供的空间组成的单个逻辑磁盘来避免这个问题,操作系统在物理磁盘上放置了一个文件系统。即使使用GEOM提供的软件RAID解决方案,位于RAID之上的UFS文件系统也认为它是在处理单个设备。ZFS的卷管理器和文件系统的组合解决了这个问题,并允许创建共享可用存储池的文件系统。ZFS对物理磁盘布局的感知的一大优势是,当向池中添加额外的磁盘时,现有的文件系统会自动增长。然后,这个新空间可供文件系统使用。ZFS还可以对每个文件系统应用不同的属性。这使得创建单独的文件系统和数据集而不是单个单片文件系统非常有用。
FreeBSD可以在系统初始化期间挂载ZFS池和数据集。要启用它,请将此行添加到 /etc/rc.conf :
xxxxxxxxxxzfs_enable="YES"然后启动服务:
xxxxxxxxxx# service zfs start本节中的示例假设有三个SCSI磁盘,设备名为da0、da1和da2。SATA硬件的用户应该使用ada设备名称。
要使用单个磁盘设备创建简单的非冗余池,请执行以下操作:
xxxxxxxxxx# zpool create example /dev/da0要查看新池,请查看 df 的输出:
xxxxxxxxxx# dfFilesystem 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% /usrexample 17547136 0 17547136 0% /example此输出显示了 example 池的创建和装载,现在可以作为文件系统访问。创建供用户浏览的文件:
xxxxxxxxxx# cd /example# ls# touch testfile# ls -altotal 4drwxr-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功能和属性。要在此池上创建启用压缩的数据集,请执行以下操作:
xxxxxxxxxx# zfs create example/compressed# zfs set compression=gzip example/compressedexample/compressed 数据集现在是ZFS压缩文件系统。尝试将一些大文件复制到 /example.compressed 。
使用以下命令禁用压缩:
xxxxxxxxxx# zfs set compression=off example/compressed要卸载文件系统,请使用 zfs umount ,然后用 df 进行验证:
xxxxxxxxxx# zfs umount example/compressed# dfFilesystem 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% /usrexample 17547008 0 17547008 0% /example要重新挂载文件系统以使其再次可访问,请使用 zfs mount 并使用 df 进行验证:
xxxxxxxxxx# zfs mount example/compressed# dfFilesystem 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% /usrexample 17547008 0 17547008 0% /exampleexample/compressed 17547008 0 17547008 0% /example/compressed运行 mount 显示池和文件系统:
xxxxxxxxxx# 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 的新文件系统。它假设文件系统包含重要文件,并将其配置为存储每个数据块的两个副本。
xxxxxxxxxx# zfs create example/data# zfs set copies=2 example/data使用 df 查看数据和空间使用情况:
xxxxxxxxxx# dfFilesystem 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% /usrexample 17547008 0 17547008 0% /exampleexample/compressed 17547008 0 17547008 0% /example/compressedexample/data 17547008 0 17547008 0% /example/data请注意,池中的所有文件系统都有相同的可用空间。在这些示例中使用 df 表明文件系统使用了它们所需的空间,并且都从同一个池中提取。ZFS摆脱了卷和分区等概念,允许多个文件系统共享同一个池。
要销毁文件系统,然后销毁不再需要的池,请执行以下操作:
xxxxxxxxxx# zfs destroy example/compressed# zfs destroy example/data# zpool destroy example磁盘故障。避免磁盘故障导致数据丢失的一种方法是使用RAID。ZFS在其池设计中支持此功能。RAID-Z池需要三个或更多磁盘,但提供的可用空间比镜像池多。
此示例创建了一个RAID-Z池,指定要添加到池中的磁盘:
xxxxxxxxxx# zpool create storage raidz da0 da1 da2xxxxxxxxxxSun™建议RAID-Z配置中使用的设备数量在3到9之间。对于需要由10个或更多磁盘组成的单个池的环境,可以考虑将其拆分为更小的RAID-Z组。如果有两个磁盘可用,ZFS镜像会在需要时提供冗余。有关更多详细信息,请参阅zpool(8)。前面的示例创建了 storage zpool。此示例在该池中创建了一个名为 home 的新文件系统:
xxxxxxxxxx# zfs create storage/home启用压缩并存储目录和文件的额外副本:
xxxxxxxxxx# zfs set copies=2 storage/home# zfs set compression=gzip storage/home要使此目录成为用户的新主目录,请将用户数据复制到此目录并创建相应的符号链接:
xxxxxxxxxx# cp -rp /home/* /storage/home# rm -rf /home /usr/home# ln -s /storage/home /home# ln -s /storage/home /usr/home用户数据现在存储在新创建的 /storage/home 上。通过添加新用户并以该用户身份登录进行测试。
创建文件系统快照以稍后回滚:
xxxxxxxxxx# zfs snapshot storage/home@08-30-08ZFS创建数据集的快照,而不是单个目录或文件。
@ 字符是文件系统名或卷名之间的分隔符。在删除重要目录之前,请备份文件系统,然后回滚到该目录仍然存在的早期快照:
xxxxxxxxxx# zfs rollback storage/home@08-30-08要列出所有可用快照,请在文件系统的 .zfs/snapshot 目录中运行ls。例如,要查看拍摄的快照:
xxxxxxxxxx# ls /storage/home/.zfs/snapshot编写一个脚本,对用户数据进行定期快照。随着时间的推移,快照可能会占用大量磁盘空间。使用以下命令删除上一个快照:
xxxxxxxxxx# zfs destroy storage/home@08-30-08测试后,使用以下命令将 /storage/home 设置为真实的 /home :
xxxxxxxxxx# zfs set mountpoint=/home storage/home运行 df 并挂载以确认系统现在将文件系统视为真实的 /home :
xxxxxxxxxx# 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)# dfFilesystem 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% /usrstorage 26320512 0 26320512 0% /storagestorage/home 26320512 0 26320512 0% /home这就完成了RAID-Z配置。通过在 /etc/periodic.conf 中添加以下行,将有关创建的文件系统的每日状态更新添加到夜间 periodic(8) 运行中:
xxxxxxxxxxdaily_status_zfs_enable="YES"每个软件RAID都有一种监视其 state 的方法。使用以下方式查看RAID-Z设备的状态:
xxxxxxxxxx# zpool status -xall pools are healthy如果出现问题,可能是磁盘处于Offline(脱机)状态,池状态将如下:
xxxxxxxxxx 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脱机:
xxxxxxxxxx# zpool offline storage da1现在关闭计算机电源并更换da1。打开计算机电源并将da1返回到池中:
xxxxxxxxxx# zpool replace storage da1接下来,再次检查状态,这次不使用-x显示所有池:
xxxxxxxxxx# 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在这个例子中,一切都很正常。
ZFS使用校验和来验证存储数据的完整性。创建文件系统会自动启用它们。
xxxxxxxxxx禁用校验和是可能的,但不建议!校验和占用很少的存储空间,并提供数据完整性。禁用校验和后,大多数ZFS功能将无法正常工作。禁用这些校验和不会显著提高性能。通过以下方式验证数据校验和(称为scrubbing,清理)可确保 stroage 池的完整性:
xxxxxxxxxx# zpool scrub storage擦除的持续时间取决于存储的数据量。更大量的数据将需要更长的时间来验证。由于清理是I/O密集型的,ZFS允许一次运行一次清理。清理完成后,使用 zpool status 查看状态:
x# zpool status storage pool: storage state: ONLINE scrub: scrub completed with 0 errors on Sat Jan 26 19:57:37 2013config: 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) 。
zpool 管理ZFS管理使用两个主要实用程序。zpool 实用程序控制池的操作,并允许添加、删除、替换和管理磁盘。zfs 实用程序允许创建、销毁和管理数据集,包括文件系统和卷。
创建ZFS存储池需要永久性的决策,因为池结构在创建后不能更改。最重要的决定是将物理磁盘分组到哪种类型的vdev中。有关可能选项的详细信息,请参阅 vdev types 列表。创建池后,大多数vdev类型不允许向vdev添加磁盘。例外情况是镜像,它允许向vdev添加新磁盘,以及条带,它通过将新磁盘连接到vdev来升级为镜像。虽然添加新的vdev会扩展池,但池创建后池布局无法更改。相反,备份数据,销毁池,然后重新创建。
创建一个简单的镜像池:
xxxxxxxxxx# zpool create mypool mirror /dev/ada1 /dev/ada2# zpool status pool: mypool state: ONLINE scan: none requestedconfig:NAME STATE READ WRITE CKSUMmypool ONLINE 0 0 0 mirror-0 ONLINE 0 0 0 ada1 ONLINE 0 0 0 ada2 ONLINE 0 0 0errors: No known data errors要使用单个命令创建多个vdev,请指定由vdev type关键字分隔的磁盘组,在本例中为 mirror :
xxxxxxxxxx# zpool create mypool mirror /dev/ada1 /dev/ada2 mirror /dev/ada3 /dev/ada4# zpool status pool: mypool state: ONLINE scan: none requestedconfig: 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放在单独的分区中,允许同一磁盘具有其他分区用于其他目的。特别是,它允许添加带有引导所需的引导代码和文件系统的分区。这允许从也是池成员的磁盘启动。当使用分区而不是整个磁盘时,ZFS不会对FreeBSD造成性能损失。使用分区还允许管理员使用低于满容量的磁盘来进行资源调配。如果未来与原始磁盘标称大小相同的替换磁盘实际上容量稍小,则使用替换磁盘时,较小的分区仍将适用。
使用分区创建RAID-Z2池:
xxxxxxxxxx# zpool create mypool raidz2 /dev/ada0p3 /dev/ada1p3 /dev/ada2p3 /dev/ada3p3 /dev/ada4p3 /dev/ada5p3# zpool status pool: mypool state: ONLINE scan: none requestedconfig: 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 强制销毁池。这可能会导致在这些数据集上有打开文件的应用程序中出现未定义的行为。
有两种方法可以将磁盘添加到池中:使用 zpool attach 将磁盘连接到现有的vdev,或使用 zpool add 将vdev添加到池。某些vdev类型允许在创建后向vdev添加磁盘。
使用单个磁盘创建的池缺乏冗余。它可以检测到损坏,但无法修复,因为没有其他数据副本。 copies 属性可能能够从坏扇区等小故障中恢复,但不能提供与镜像或RAIDZ相同的保护级别。从由单个磁盘vdev组成的池开始,使用 zpool attach 向vdev添加新磁盘,创建镜像。还可以使用 zpool attach 将新磁盘添加到镜像组中,从而提高冗余和读取性能。在对用于池的磁盘进行分区时,将第一个磁盘的布局复制到第二个磁盘上。使用 gpart backup 和 gpart restore 使此过程更容易。
通过连接 ada1p3 将单磁盘(条带)vdev ada0p3 升级为镜像:
xxxxxxxxxx# zpool status pool: mypool state: ONLINE scan: none requestedconfig: NAME STATE READ WRITE CKSUM mypool ONLINE 0 0 0 ada0p3 ONLINE 0 0 0 errors: No known data errors# zpool attach mypool ada0p3 ada1p3Make 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 ada1bootcode written to ada1# zpool status pool: mypool state: ONLINEstatus: 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% doneconfig: 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 2014config: 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都提供自己的冗余。可以混合 mirror 和 RAID-Z 等vdev类型,但不建议这样做。将非冗余vdev添加到包含镜像或RAID-Z vdev的池中会危及整个池上的数据。分布式写入意味着非冗余磁盘的故障将导致写入池的每个块的一小部分丢失。
ZFS在每个vdev上条带化数据。例如,对于两个镜像vdev,这实际上是一个RAID 10,它在两组镜像上进行条带写入。ZFS分配空间,使每个vdev同时达到100%满。具有不同可用空间量的vdev会降低性能,因为更多的数据写入到不太满的vdev。
将新设备连接到启动池时,请记住更新启动代码。
将第二个镜像组(ada2p3和ada3p3)连接到现有镜像:
xxxxxxxxxx# zpool status pool: mypool state: ONLINE scan: resilvered 781M in 0h0m with 0 errors on Fri May 30 08:19:35 2014config: 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 ada2bootcode written to ada2# gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ada3bootcode 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 2014config: 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是不可能的,如果有足够的剩余冗余,则从镜像中删除磁盘是独占的。如果镜像组中仍有一个磁盘,则该组将不再是镜像,而变成条带,如果剩余磁盘发生故障,整个池都将面临风险。
从三向镜像组中卸下磁盘:
xxxxxxxxxx# zpool status pool: mypool state: ONLINE scan: scrub repaired 0 in 0h0m with 0 errors on Fri May 30 08:29:51 2014config: 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 2014config: 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池状态很重要。如果驱动器脱机或ZFS检测到读取、写入或校验和错误,相应的错误计数会增加。 status 输出显示池中每个设备的配置和状态以及整个池的状态。还显示了要采取的行动和上次擦洗的详细信息。
xxxxxxxxxx# zpool status pool: mypool state: ONLINE scan: scrub repaired 0 in 2h25m with 0 errors on Sat Sep 14 04:25:50 2013config: 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当检测到错误时,ZFS会增加读取、写入或校验和错误计数。清除错误消息,并使用 zpool clear mypool 重置计数。清除错误状态对于在池遇到错误时向管理员发出警报的自动脚本非常重要。如果不清除旧错误,脚本可能无法报告进一步的错误。
可能需要用不同的磁盘替换一个磁盘。更换工作磁盘时,该过程会在更换过程中使旧磁盘保持在线。池永远不会进入 degraded 状态,从而降低了数据丢失的风险。运行 zpool replace 会将数据从旧磁盘复制到新磁盘。操作完成后,ZFS将旧磁盘与vdev断开连接。如果新磁盘比旧磁盘大,则可以使用新空间来扩展zpool。请参阅【22.3.9. 增长池】。
更换池中正常工作的设备:
xxxxxxxxxx# zpool status pool: mypool state: ONLINE scan: none requestedconfig: 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 ada2p3Make 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 thefollowing 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: ONLINEstatus: 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% doneconfig: 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 2014config: 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当池中的磁盘发生故障时,该磁盘所属的vdev将进入 degraded 状态。数据仍然可用,但性能降低,因为ZFS从可用冗余中计算缺失的数据。要将vdev恢复到完全功能状态,请更换发生故障的物理设备。然后指示ZFS开始 resilver 操作。ZFS根据可用冗余重新计算故障设备上的数据,并将其写入替换设备。完成后,vdev将返回 online 状态。
如果vdev没有任何冗余,或者如果设备发生故障并且没有足够的冗余来补偿,则池将进入 faulted 状态。除非有足够的设备可以重新连接,否则池将无法运行,需要从备份中恢复数据。
更换故障磁盘时,故障磁盘的名称将更改为新磁盘的GUID。如果替换设备具有相同的设备名称,则不需要为 zpool replace 设置新的设备名称参数。
使用 zpool replace 替换故障磁盘:
xxxxxxxxxx# zpool status pool: mypool state: DEGRADEDstatus: 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 requestedconfig: 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: DEGRADEDstatus: 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% doneconfig: 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 2014config: 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定期 scrub (擦洗)池,最好每月至少一次。scrub 操作是磁盘密集型的,会降低运行时的性能。在安排 scrub 时避免高需求时段,或使用 vfs.zfs.crub_delay 调整 scrub 的相对优先级,以防止其减缓其他工作负载。
xxxxxxxxxx# 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% doneconfig: 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 。
与数据块一起存储的校验和使文件系统能够 self-heal(自我修复)。此功能将自动修复校验和与存储池中另一个设备上记录的校验和不匹配的数据。例如,具有两个磁盘的镜像配置,其中一个驱动器开始出现故障,无法再正确存储数据。当数据长时间未被访问时,情况会更糟,就像长期存档存储一样。传统的文件系统需要运行检查和修复数据的命令,如 fsck(8) 。这些命令需要时间,在严重的情况下,管理员必须决定执行哪种修复操作。当ZFS检测到校验和不匹配的数据块时,它会尝试从镜像磁盘读取数据。如果该磁盘可以提供正确的数据,ZFS会将其提供给应用程序,并使用错误的校验和更正磁盘上的数据。在正常池操作期间,无需系统管理员进行任何交互即可发生这种情况。
下一个示例通过创建镜像磁盘池 /dev/ada0 和 /dev/ada1 来显示这种自愈行为。
xxxxxxxxxx# zpool create healer mirror /dev/ada0 /dev/ada1# zpool status healer pool: healer state: ONLINE scan: none requestedconfig: 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 listNAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOThealer 960M 92.5K 960M - - 0% 0% 1.00x ONLINE -使用自愈功能将一些重要数据复制到池中以防止数据错误,并创建池的校验和以供以后比较。
xxxxxxxxxx# cp /some/important/data /healer# zfs listNAME SIZE ALLOC FREE CAP DEDUP HEALTH ALTROOThealer 960M 67.7M 892M 7% 1.00x ONLINE -# sha1 /healer > checksum.txt# cat checksum.txtSHA1 (/healer) = 2753eff56d77d9a536ece6694bf0a82740344d1f通过将随机数据写入镜像中某个磁盘的开头来模拟数据损坏。为了防止ZFS在检测到数据时修复数据,请在损坏之前导出池,然后再次导入。
xxxxxxxxxx这是一个危险的操作,可能会破坏重要数据,此处仅用于演示。请勿在存储池正常运行期间尝试。此故意损坏示例也不应在任何文件系统未在另一个分区上使用ZFS的磁盘上运行。不要使用池中以外的任何其他磁盘设备名称。确保存在正确的池备份,并在运行命令之前对其进行测试!xxxxxxxxxx# zpool export healer# dd if=/dev/random of=/dev/ada1 bs=1m count=200200+0 records in200+0 records out209715200 bytes transferred in 62.992162 secs (3329227 bytes/sec)# zpool import healer池状态显示一个设备发生了错误。请注意,从池中读取数据的应用程序没有收到任何不正确的数据。ZFS从ada0设备提供了具有正确校验和的数据。要查找校验和错误的设备,请查找CKSUM列包含非零值的设备。
xxxxxxxxxx# zpool status healer pool: healer state: ONLINEstatus: 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 requestedconfig: 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 errorsZFS检测到错误,并使用未受影响的ada0镜像磁盘中存在的冗余进行处理。与原始校验和的比较将揭示池是否再次一致。
xxxxxxxxxx# sha1 /healer >> checksum.txt# cat checksum.txtSHA1 (/healer) = 2753eff56d77d9a536ece6694bf0a82740344d1fSHA1 (/healer) = 2753eff56d77d9a536ece6694bf0a82740344d1f在故意篡改前后生成校验和,同时池数据仍然匹配。这显示了ZFS如何在校验和不同时自动检测和纠正任何错误。请注意,如果池中有足够的冗余,这是可能的。由单个设备组成的池没有自愈能力。这也是为什么校验和在ZFS中如此重要的原因;不要以任何理由禁用它们。ZFS不需要 fsck(8) 或类似的文件系统一致性检查程序来检测和纠正这一点,并在出现问题时保持池可用。现在需要执行擦除操作来覆盖ada1上损坏的数据。
xxxxxxxxxx# zpool scrub healer# zpool status healer pool: healer state: ONLINEstatus: 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% doneconfig: 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 )输出所示。操作完成后,池状态更改为:
xxxxxxxxxx# zpool status healer pool: healer state: ONLINEstatus: 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 2012config: 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.72Kerrors: No known data errors在清理操作完成并将所有数据从ada0同步到ada1后,通过运行 zpool clear 从池状态中清除错误消息。
xxxxxxxxxx# 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 2012config: 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池现在已恢复到完全工作状态,所有错误计数现在为零。
每个vdev中最小的设备限制了冗余池的可用大小。用较大的设备替换最小的设备。在完成 replace 或 resilver 操作后,池可以增长以使用新设备的容量。例如,考虑1 TB驱动器和2 TB驱动器的镜像。可用空间为1TB。当用另一个2 TB的驱动器替换1 TB的驱动器时,重置过程会将现有数据复制到新驱动器上。由于这两个设备现在都有2 TB的容量,镜像的可用空间增长到2 TB。
在每台设备上使用 zpool online -e 开始扩展。扩展所有设备后,多余的空间可供池使用。
在将池移动到另一个系统之前导出池。ZFS卸载所有数据集,将每个设备标记为已导出,但仍锁定以防止其他磁盘使用。这允许在其他机器、支持ZFS的其他操作系统甚至不同的硬件架构上导入池(有一些注意事项,请参阅 zpool(8) )。当数据集有打开的文件时,使用 zpool export -f 强制导出池。请谨慎使用。数据集被强制卸载,这可能会导致在这些数据集上打开文件的应用程序出现意外行为。
导出未使用的池:
xxxxxxxxxx# zpool export mypool导入池会自动装载数据集。如果这是不希望的行为,请使用 zpool import -N 来防止它。zpool import -o 为此特定导入设置临时属性。zpool import altroot= 允许导入具有基本挂载点而不是文件系统根的池。如果该池上次是在其他系统上使用的,并且没有正确导出,请使用 zpool import -f 。zpool import -a 强制导入所有似乎没有被其他系统使用的池。
列出所有可导入的池:
xxxxxxxxxx# zpool import pool: mypool id: 9930174748043525076 state: ONLINEaction: The pool can be imported using its name or numeric identifier.config: mypool ONLINE ada2p3 ONLINE使用备用根目录导入池:
xxxxxxxxxx# zpool import -o altroot=/mnt mypool# zfs listzfs listNAME USED AVAIL REFER MOUNTPOINTmypool 110K 47.0G 31K /mnt/mypool升级FreeBSD后,或者如果从使用旧版本的系统导入池,请手动将池升级到最新的ZFS版本以支持新功能。考虑在升级之前,池是否需要在旧系统上导入。升级是一个单向的过程。升级旧池是可能的,但降级具有新功能的池是不可能的。
升级v28池以支持 Feature Flags(功能标志):
xxxxxxxxxx# zpool status pool: mypool state: ONLINEstatus: 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 requestedconfig: 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 upgradeThis 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 mypoolUse 'zpool upgrade -v' for a list of available legacy versions.Every feature flags pool has all supported features enabled.# zpool upgrade mypoolThis 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 uograde 完成之前,ZFS的新功能将不可用。使用 zpool upgrade -v 查看升级提供了哪些新功能,以及已经支持哪些功能。
升级池以支持新功能标志:
xxxxxxxxxx# zpool status pool: mypool state: ONLINEstatus: 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 requestedconfig: 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 upgradeThis system supports ZFS pool feature flags.All pools are formatted using feature flags.Some supported features are not enabled on the following pools. Once afeature is enabled the pool may become incompatible with softwarethat 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 mypoolThis system supports ZFS pool feature flags.Enabled the following features on 'mypool': spacemap_histogram enabled_txg hole_birth extensible_dataset bookmarks filesystem_limitsxxxxxxxxxx更新从池启动的系统上的启动代码,以支持新的池版本。在包含引导代码的分区上使用 `gpart bootcode` 。根据系统的启动方式,有两种类型的启动代码可供选择:GPT(最常见的选项)和EFI(适用于更现代的系统)。对于使用GPT的传统启动,请使用以下命令: # gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ada1对于使用EFI引导的系统,请执行以下命令: # gpart bootcode -p /boot/boot1.efi -i 1 ada1将引导代码应用于池中的所有可引导磁盘。更多信息请参见gpart(8)。ZFS记录更改池的命令,包括创建数据集、更改属性或替换磁盘。查看池创建的历史记录很有用,检查哪个用户何时执行了特定操作也是如此。历史记录不保存在日志文件中,而是池本身的一部分。查看此历史记录的命令恰如其分地命名为 zpool history :
xxxxxxxxxx# zpool historyHistory for 'tank':2013-02-26.23:02:35 zpool create tank mirror /dev/ada0 /dev/ada12013-02-27.18:50:58 zfs set atime=off tank2013-02-27.18:51:09 zfs set checksum=fletcher4 tank2013-02-27.18:51:18 zfs create tank/backup输出显示 zpool 和 zfs 命令以某种方式更改池以及时间戳。不包括 zfs list 等命令。当未指定池名时,ZFS会显示所有池的历史记录。
当提供选项 -i 或 -l 时,zpool history 历史可以显示更多信息。-i 显示用户发起的事件以及内部记录的ZFS事件。
xxxxxxxxxx# zpool history -iHistory for 'tank':2013-02-26.23:02:35 [internal pool create txg:5] pool spa 28; zfs spa 28; zpl 5;uts9.1-RELEASE 901000 amd642013-02-27.18:50:53 [internal property set txg:50] atime=0 dataset = 212013-02-27.18:50:58 zfs set atime=off tank2013-02-27.18:51:04 [internal property set txg:53] checksum=7 dataset = 212013-02-27.18:51:09 zfs set checksum=fletcher4 tank2013-02-27.18:51:13 [internal create txg:55] dataset = 392013-02-27.18:51:18 zfs create tank/backup通过添加 -l 显示更多详细信息。以长格式显示历史记录,包括发出命令的用户名称和发生更改的主机名等信息。
xxxxxxxxxx# zpool history -lHistory 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 记录中,为任何给定的池提供尽可能详细的信息。池历史记录在跟踪执行的操作或需要更详细的调试输出时提供了有价值的信息。
内置的监控系统可以实时显示池I/O统计数据。它显示了池上的可用和已用空间量、每秒执行的读写操作以及使用的I/O带宽。默认情况下,ZFS监视并显示系统中的所有池。提供池名称以将监视限制到该池。一个基本的例子:
xxxxxxxxxx# zpool iostat capacity operations bandwidthpool alloc free read write read write----- ----- ----- ----- ----- ----- -----data 288G 1.53T 2 11 11.3K 57.1K要连续查看I/O活动,请指定一个数字作为最后一个参数,表示更新之间的等待间隔(秒)。每个间隔后打印下一个统计行。按 Ctrl+C 停止此连续监视。在间隔后的命令行上给出第二个数字,以指定要显示的统计总数。
使用 -v 显示更详细的I/O统计信息。池中的每个设备都会显示一条统计线。这对于查看每个设备上执行的读写操作非常有用,并且可以帮助确定是否有任何单个设备减慢了池的速度。此示例显示了一个具有两个设备的镜像池:
xxxxxxxxxx# zpool iostat -v capacity operations bandwidthpool alloc free read write read write--------- ----- ------ ---- ----- ----- ----- data 288G 1.53T 2 12 9.23K 61.5Kmirror 288G 1.53T 2 12 9.23K 61.5Kada1 - - 0 4 5.61K 61.7Kada2 - - 1 4 5.04K 61.7K--------- ----- ----- ----- ----- ------ -----ZFS可以将由一个或多个镜像vdev组成的池拆分为两个池。除非另有说明,否则ZFS会分离每个镜像的最后一个成员,并创建一个包含相同数据的新池。一定要先用 -n 对操作进行模拟。这显示了所请求操作的详细信息,而没有实际执行它。这有助于确认操作将按照用户的意图进行。
zfs 管理zfs 实用程序可以创建、销毁和管理池中所有现有的ZFS数据集。要管理池本身,请使用 zpool 。
与传统的磁盘和卷管理器不同,ZFS中的空间不是预先分配的。对于传统的文件系统,在分区和分配空间后,如果不添加新磁盘,就无法添加新的文件系统。使用ZFS,可以随时创建新的文件系统。每个数据集 都有属性,包括压缩(compression)、重复数据删除(deduplication)、缓存(caching)和配额(quota)等功能,以及只读、区分大小写、网络文件共享和装载点等其他有用属性。数据集可以相互嵌套,子数据集将继承其祖先的属性。委托(delegate)、复制(replicate)、快照(snapshot)、jail允许将每个数据集作为一个单元进行管理和销毁。为每种不同类型或一组文件创建单独的数据集具有优势。拥有大量数据集的缺点是,像 zfs list 这样的一些命令会变慢,装载数百甚至数千个数据集会减缓FreeBSD的启动过程。
创建一个新的数据集并对其启用LZ4压缩:
xxxxxxxxxx# zfs listNAME USED AVAIL REFER MOUNTPOINTmypool 781M 93.2G 144K nonemypool/ROOT 777M 93.2G 144K nonemypool/ROOT/default 777M 93.2G 777M /mypool/tmp 176K 93.2G 176K /tmpmypool/usr 616K 93.2G 144K /usrmypool/usr/home 184K 93.2G 184K /usr/homemypool/usr/ports 144K 93.2G 144K /usr/portsmypool/usr/src 144K 93.2G 144K /usr/srcmypool/var 1.20M 93.2G 608K /varmypool/var/crash 148K 93.2G 148K /var/crashmypool/var/log 178K 93.2G 178K /var/logmypool/var/mail 144K 93.2G 144K /var/mailmypool/var/tmp 152K 93.2G 152K /var/tmp# zfs create -o compress=lz4 mypool/usr/mydataset# zfs listNAME USED AVAIL REFER MOUNTPOINTmypool 781M 93.2G 144K nonemypool/ROOT 777M 93.2G 144K nonemypool/ROOT/default 777M 93.2G 777M /mypool/tmp 176K 93.2G 176K /tmpmypool/usr 704K 93.2G 144K /usrmypool/usr/home 184K 93.2G 184K /usr/homemypool/usr/mydataset 87.5K 93.2G 87.5K /usr/mydatasetmypool/usr/ports 144K 93.2G 144K /usr/portsmypool/usr/src 144K 93.2G 144K /usr/srcmypool/var 1.20M 93.2G 610K /varmypool/var/crash 148K 93.2G 148K /var/crashmypool/var/log 178K 93.2G 178K /var/logmypool/var/mail 144K 93.2G 144K /var/mailmypool/var/tmp 152K 93.2G 152K /var/tmp销毁数据集比删除数据集上的文件快得多,因为它不涉及扫描文件和更新相应的元数据。
销毁创建的数据集:
xxxxxxxxxx# zfs listNAME USED AVAIL REFER MOUNTPOINTmypool 880M 93.1G 144K nonemypool/ROOT 777M 93.1G 144K nonemypool/ROOT/default 777M 93.1G 777M /mypool/tmp 176K 93.1G 176K /tmpmypool/usr 101M 93.1G 144K /usrmypool/usr/home 184K 93.1G 184K /usr/homemypool/usr/mydataset 100M 93.1G 100M /usr/mydatasetmypool/usr/ports 144K 93.1G 144K /usr/portsmypool/usr/src 144K 93.1G 144K /usr/srcmypool/var 1.20M 93.1G 610K /varmypool/var/crash 148K 93.1G 148K /var/crashmypool/var/log 178K 93.1G 178K /var/logmypool/var/mail 144K 93.1G 144K /var/mailmypool/var/tmp 152K 93.1G 152K /var/tmp# zfs destroy mypool/usr/mydataset# zfs listNAME USED AVAIL REFER MOUNTPOINTmypool 781M 93.2G 144K nonemypool/ROOT 777M 93.2G 144K nonemypool/ROOT/default 777M 93.2G 777M /mypool/tmp 176K 93.2G 176K /tmpmypool/usr 616K 93.2G 144K /usrmypool/usr/home 184K 93.2G 184K /usr/homemypool/usr/ports 144K 93.2G 144K /usr/portsmypool/usr/src 144K 93.2G 144K /usr/srcmypool/var 1.21M 93.2G 612K /varmypool/var/crash 148K 93.2G 148K /var/crashmypool/var/log 178K 93.2G 178K /var/logmypool/var/mail 144K 93.2G 144K /var/mailmypool/var/tmp 152K 93.2G 152K /var/tmp在ZFS的现代版本中, zfs destroy 是异步的,可用空间可能需要几分钟才能出现在池中。使用 zpool get freesing poolname 查看 freesing 属性,该属性显示哪些数据集在后台释放了块。如果有子数据集,如快照或其他数据集,则不可能销毁父数据集。要销毁数据集及其子数据集,请使用 -r 递归销毁数据集和子数据集。使用 -n -v 列出此操作销毁的数据集和快照,而不会实际销毁任何内容。还显示了通过销毁快照回收的空间。
卷(volume)是一种特殊的数据集类型。与其作为文件系统挂载,不如将其作为块设备暴露在 /dev/zvol/poolname/dataset 下。这允许将卷用于其他文件系统,备份虚拟机的磁盘,或使用iSCSI或HAST等协议将其提供给其他网络主机。
使用任何文件系统或不使用文件系统来格式化卷以存储原始数据。对用户来说,卷似乎是一个普通磁盘。将普通文件系统放在这些 zvols 上提供了普通磁盘或文件系统所没有的功能。例如,在250 MB卷上使用压缩属性可以创建压缩的FAT文件系统。
xxxxxxxxxx# zfs create -V 250m -o compression=on tank/fat32# zfs list tankNAME USED AVAIL REFER MOUNTPOINTtank 258M 670M 31K /tank# newfs_msdos -F32 /dev/zvol/tank/fat32# mount -t msdosfs /dev/zvol/tank/fat32 /mnt# df -h /mnt | grep fat32Filesystem 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)销毁卷与销毁常规文件系统数据集非常相似。该操作几乎是即时的,但可能需要几分钟才能在后台回收可用空间。
要更改数据集的名称,请使用 zfs rename 。要更改数据集的父级,也可以使用此命令。将数据集重命名为具有不同的父数据集将更改从父数据集继承的那些属性的值。重命名数据集会卸载数据集,然后将其重新装载到新位置(从新的父数据集继承)。要防止这种行为,请使用 -u 。
重命名数据集并将其移动到其他父数据集下:
xxxxxxxxxx# zfs listNAME USED AVAIL REFER MOUNTPOINTmypool 780M 93.2G 144K nonemypool/ROOT 777M 93.2G 144K nonemypool/ROOT/default 777M 93.2G 777M /mypool/tmp 176K 93.2G 176K /tmpmypool/usr 704K 93.2G 144K /usrmypool/usr/home 184K 93.2G 184K /usr/homemypool/usr/mydataset 87.5K 93.2G 87.5K /usr/mydatasetmypool/usr/ports 144K 93.2G 144K /usr/portsmypool/usr/src 144K 93.2G 144K /usr/srcmypool/var 1.21M 93.2G 614K /varmypool/var/crash 148K 93.2G 148K /var/crashmypool/var/log 178K 93.2G 178K /var/logmypool/var/mail 144K 93.2G 144K /var/mailmypool/var/tmp 152K 93.2G 152K /var/tmp# zfs rename mypool/usr/mydataset mypool/var/newname# zfs listNAME USED AVAIL REFER MOUNTPOINTmypool 780M 93.2G 144K nonemypool/ROOT 777M 93.2G 144K nonemypool/ROOT/default 777M 93.2G 777M /mypool/tmp 176K 93.2G 176K /tmpmypool/usr 616K 93.2G 144K /usrmypool/usr/home 184K 93.2G 184K /usr/homemypool/usr/ports 144K 93.2G 144K /usr/portsmypool/usr/src 144K 93.2G 144K /usr/srcmypool/var 1.29M 93.2G 614K /varmypool/var/crash 148K 93.2G 148K /var/crashmypool/var/log 178K 93.2G 178K /var/logmypool/var/mail 144K 93.2G 144K /var/mailmypool/var/newname 87.5K 93.2G 87.5K /var/newnamemypool/var/tmp 152K 93.2G 152K /var/tmp重命名快照使用相同的命令。由于快照的性质,重命名无法更改其父数据集。要重命名递归快照,请指定 -r ;这也将重命名子数据集中同名的所有快照。
xxxxxxxxxx# zfs list -t snapshotNAME USED AVAIL REFER MOUNTPOINTmypool/var/newname@first_snapshot 0 - 87.5K -# zfs rename mypool/var/newname@first_snapshot new_snapshot_name# zfs list -t snapshotNAME USED AVAIL REFER MOUNTPOINTmypool/var/newname@new_snapshot_name 0 - 87.5K -每个ZFS数据集都有控制其行为的属性。大多数属性都是从父数据集自动继承的,但可以在本地覆盖。使用 zfs set property=value dataset 在数据集上设置属性。大多数属性都有一组有限的有效值,zfs get 将显示每个可能的属性和有效值。使用 zfs inherit 会将大多数属性恢复为其继承的值。用户定义的属性也是可能的。它们成为数据集配置的一部分,并提供有关数据集或其内容的更多信息。要将这些自定义属性与作为ZFS的一部分提供的属性区分开来,请使用冒号(:)为属性创建自定义名称空间。
xxxxxxxxxx# zfs set custom:costcenter=1234 tank# zfs get custom:costcenter tankNAME PROPERTY VALUE SOURCEtank custom:costcenter 1234 local要删除自定义属性,请使用带有-r的zfs inherite。如果自定义属性未在任何父数据集中定义,则此选项会将其删除(但池的历史记录仍会记录更改)。
xxxxxxxxxx# zfs inherit -r custom:costcenter tank# zfs get custom:costcenter tankNAME PROPERTY VALUE SOURCEtank custom:costcenter - -# zfs get all tank | grep custom:costcenter#NFS和SMB共享选项是两个常用且有用的数据集属性。设置这些定义了ZFS是否以及如何在网络上共享数据集。目前,FreeBSD支持单独设置NFS共享。要获取共享的当前状态,请输入:
xxxxxxxxxx# zfs get sharenfs mypool/usr/homeNAME PROPERTY VALUE SOURCEmypool/usr/home sharenfs on local# zfs get sharesmb mypool/usr/homeNAME PROPERTY VALUE SOURCEmypool/usr/home sharesmb off local要启用数据集共享,请输入:
xxxxxxxxxx# zfs set sharenfs=on mypool/usr/home设置通过NFS共享数据集的其他选项,如 -alldirs、-maproot 和 -network 。要设置通过NFS分享的数据集的选项,请输入:
xxxxxxxxxx# zfs set sharenfs="-alldirs,-maproot=root,-network=192.168.1.0/24" mypool/usr/home快照是ZFS最强大的功能之一。快照提供数据集的只读、点时间(point-in-time)副本。使用写时复制(Copy-On-Write,COW),ZFS通过在磁盘上保留旧版本的数据来快速创建快照。如果不存在快照,ZFS会在重写或删除数据时回收空间以供将来使用。快照通过仅记录当前数据集和以前版本之间的差异来保留磁盘空间。允许对整个数据集进行快照,而不是对单个文件或目录进行快照。数据集中的快照会复制其中包含的所有内容。这包括文件系统属性、文件、目录、权限等。快照在首次创建时不会使用额外的空间,但会随着它们引用的块的变化而消耗空间。使用 -r 拍摄的递归快照在数据集及其子数据集上创建同名快照,提供文件系统的一致时间快照。当应用程序在相关数据集上有文件或相互依赖时,这可能很重要。如果没有快照,备份将包含来自不同时间点的文件副本。
ZFS中的快照提供了其他具有快照功能的文件系统所缺乏的各种功能。快照使用的一个典型示例是在执行软件安装或系统升级等有风险的操作时,作为备份文件系统当前状态的快速方法。如果操作失败,回滚到快照会使系统返回到创建快照时的相同状态。如果升级成功,请删除快照以释放空间。如果没有快照,失败的升级通常需要恢复备份,这是乏味、耗时的,并且可能需要停机,在此期间系统无法使用。即使在系统正常运行且停机时间很少或没有停机的情况下,回滚到快照也很快。考虑到从备份中复制数据所需的时间,使用数TB的存储系统可以节省大量时间。快照不能替代池的完整备份,但提供了一种在特定时间存储数据集副本的快速简便的方法。
要创建快照,请使用 zfs snapshot dataset@snapshotname 。添加 -r 会递归创建一个快照,在所有子数据集上使用相同的名称(@及后面的snapshotname)。
创建整个池的递归快照:
xxxxxxxxxx# zfs list -t allNAME USED AVAIL REFER MOUNTPOINTmypool 780M 93.2G 144K nonemypool/ROOT 777M 93.2G 144K nonemypool/ROOT/default 777M 93.2G 777M /mypool/tmp 176K 93.2G 176K /tmpmypool/usr 616K 93.2G 144K /usrmypool/usr/home 184K 93.2G 184K /usr/homemypool/usr/ports 144K 93.2G 144K /usr/portsmypool/usr/src 144K 93.2G 144K /usr/srcmypool/var 1.29M 93.2G 616K /varmypool/var/crash 148K 93.2G 148K /var/crashmypool/var/log 178K 93.2G 178K /var/logmypool/var/mail 144K 93.2G 144K /var/mailmypool/var/newname 87.5K 93.2G 87.5K /var/newnamemypool/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 snapshotNAME USED AVAIL REFER MOUNTPOINTmypool@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 列中没有提到可用磁盘空间,因为快照在创建后是只读的。将快照与原始数据集进行比较:
xxxxxxxxxx# zfs list -rt all mypool/usr/homeNAME USED AVAIL REFER MOUNTPOINTmypool/usr/home 184K 93.2G 184K /usr/homemypool/usr/home@my_recursive_snapshot 0 - 184K -同时显示数据集和快照可以揭示快照是如何以COW方式工作的。它们保存所做的更改(delta,增量),而不是重新保存完整的文件系统内容。这意味着快照在进行更改时占用的空间很小。通过将文件复制到数据集,然后创建第二个快照,可以更深入地观察空间使用情况:
xxxxxxxxxx# cp /etc/passwd /var/tmp# zfs snapshot mypool/var/tmp@after_cp# zfs list -rt all mypool/var/tmpNAME USED AVAIL REFER MOUNTPOINTmypool/var/tmp 206K 93.2G 118K /var/tmpmypool/var/tmp@my_recursive_snapshot 88K - 152K -mypool/var/tmp@after_cp 0 - 118K -第二个快照包含复制操作后对数据集的更改。这节省了大量空间。请注意,快照 mypool/var/tmp@my_recursive_snapshot 的大小在 USED 列中也发生了变化,以显示其自身与之后拍摄的快照之间的变化。
ZFS提供了一个内置命令来比较两个快照之间的内容差异。当用户想要查看文件系统随时间的变化时,这对于随时间拍摄的许多快照很有帮助。例如, zfs diff 允许用户查找仍然包含意外删除的文件的最新快照。对上一节中创建的两个快照执行此操作会产生以下输出:
xxxxxxxxxx# zfs list -rt all mypool/var/tmpNAME USED AVAIL REFER MOUNTPOINTmypool/var/tmp 206K 93.2G 118K /var/tmpmypool/var/tmp@my_recursive_snapshot 88K - 152K -mypool/var/tmp@after_cp 0 - 118K -# zfs diff mypool/var/tmp@my_recursive_snapshotM /var/tmp/+ /var/tmp/passwd该命令列出了指定快照(在本例中为 mypool/var/tmp@my_recursive_snapshot )和实时文件系统之间的更改。第一列显示更改类型:
| 类型 | 说明 |
|---|---|
| + | 添加路径或文件。 |
| - | 删除路径或文件。 |
| M | 修改路径或文件。 |
| R | 重命名路径或文件 |
将输出与表进行比较,很明显ZFS在创建快照 mypool/var/tmp@my_recursive_snapshot 后添加了passwd。这也导致了对 /var/tmp上挂载的父目录的修改。
当使用ZFS复制功能将数据集传输到不同的主机进行备份时,比较两个快照很有帮助。
通过提供两个数据集的完整数据集名称和快照名称来比较两个快照:
xxxxxxxxxx# 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_snapshotM /var/tmp/+ /var/tmp/passwd+ /var/tmp/passwd.copy# zfs diff mypool/var/tmp@my_recursive_snapshot mypool/var/tmp@after_cpM /var/tmp/+ /var/tmp/passwd备份管理员可以比较从发送主机接收到的两个快照,并确定数据集中的实际更改。有关更多信息,请参阅【22.4.7. 复制】部分。
当至少有一个快照可用时,可以随时回滚到该快照。最常见的情况是,数据集的当前状态不再有效,或者更喜欢旧版本。本地开发测试出错、糟糕的系统更新阻碍了系统功能,或者需要恢复已删除的文件或目录等情况都很常见。要回滚快照,请使用 zfs rollback snapshotname 。如果存在很多变化,操作将需要很长时间。在此期间,数据集始终保持一致的状态,就像符合ACID原则的数据库正在执行回滚一样。当数据集处于活动状态且无需停机即可访问时,就会发生这种情况。快照回滚后,数据集的状态与最初拍摄快照时的状态相同。回滚到快照会丢弃该数据集中不属于快照的所有其他数据。当以后需要一些数据时,在回滚到上一个状态之前拍摄数据集当前状态的快照是一个好主意。这样,用户可以在快照之间来回滚动,而不会丢失仍然有价值的数据。
在第一个示例中,回滚快照是因为粗心的 rm 操作删除了比预期更多的数据。
xxxxxxxxxx# zfs list -rt all mypool/var/tmpNAME USED AVAIL REFER MOUNTPOINTmypool/var/tmp 262K 93.2G 120K /var/tmpmypool/var/tmp@my_recursive_snapshot 88K - 152K -mypool/var/tmp@after_cp 53.5K - 118K -mypool/var/tmp@diff_snapshot 0 - 120K -# ls /var/tmppasswd passwd.copy vi.recover# rm /var/tmp/passwd*# ls /var/tmpvi.recover此时,用户注意到额外文件被删除,并希望将其恢复。ZFS提供了一种简单的方法,可以在定期执行重要数据的快照时使用回滚将其恢复。要获取文件并从上一个快照重新开始,请发出以下命令:
xxxxxxxxxx# zfs rollback mypool/var/tmp@diff_snapshot# ls /var/tmppasswd passwd.copy vi.recover回滚操作将数据集还原到上一个快照的状态。也可以回滚到更早拍摄的快照和之后拍摄的其他快照。尝试执行此操作时,ZFS将发出以下警告:
xxxxxxxxxx# zfs list -rt snapshot mypool/var/tmpAME USED AVAIL REFER MOUNTPOINTmypool/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_snapshotcannot rollback to 'mypool/var/tmp@my_recursive_snapshot': more recent snapshots existuse '-r' to force deletion of the following snapshots:mypool/var/tmp@after_cpmypool/var/tmp@diff_snapshot此警告意味着数据集的当前状态和用户想要回滚到的快照之间存在快照。要完成回滚,请删除这些快照。ZFS无法跟踪数据集不同状态之间的所有变化,因为快照是只读的。ZFS不会删除受影响的快照,除非用户指定 -r 以确认这是所需的操作。如果这是意图,并且了解丢失所有中间快照的后果,请发出以下命令:
xxxxxxxxxx# zfs rollback -r mypool/var/tmp@my_recursive_snapshot# zfs list -rt snapshot mypool/var/tmpNAME USED AVAIL REFER MOUNTPOINTmypool/var/tmp@my_recursive_snapshot 8K - 152K -# ls /var/tmpvi.recoverzfs list -t snapshot 的输出确认了由于 zfs rollback -r 而删除了中间快照。
快照位于父数据集下的一个隐藏目录中:.zfs/Snapshots/snapshotname 。默认情况下,即使执行标准 ls -a ,这些目录也不会显示。虽然目录没有显示,但可以像访问任何普通目录一样访问它。名为 snapdir 的属性控制这些隐藏目录是否显示在目录列表中。将属性设置为 visible 允许它们出现在 ls 和其他处理目录内容的命令的输出中。
xxxxxxxxxx# zfs get snapdir mypool/var/tmpNAME PROPERTY VALUE SOURCEmypool/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目录中还原文件:
xxxxxxxxxx# rm /var/tmp/passwd# ls -a /var/tmp. .. .zfs vi.recover# ls /var/tmp/.zfs/snapshotafter_cp my_recursive_snapshot# ls /var/tmp/.zfs/snapshot/after_cppasswd vi.recover# cp /var/tmp/.zfs/snapshot/after_cp/passwd /var/tmp即使 snapdir 属性设置为 hidden ,运行 ls .zfs/snapshot 仍将列出该目录的内容。管理员决定是否显示这些目录。这是一个针对每个数据集的设置。从这个隐藏的 .zfs/snapshot 复制文件或目录很简单。反过来尝试会导致此错误:
xxxxxxxxxx# 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 destroydataset@snapshot 。递归添加 -r 会删除父数据集下所有同名快照。在命令中添加 -n -v 将显示要删除的快照列表以及在不执行实际销毁操作的情况下将回收的空间估计值。
克隆是快照的副本,更像是常规数据集。与快照不同,克隆是可写和可装载的,并且有自己的属性。使用 zfs clone 创建克隆后,不可能销毁原始快照。要反转克隆和快照之间的子/父关系,请使用 zfs promote 。升级克隆会使快照成为克隆的子级,而不是原始父数据集的子级。这将改变ZFS对空间的计算方式,但实际上不会改变消耗的空间量。可以将克隆装载到ZFS文件系统层次结构中的任何位置,而不仅仅是快照的原始位置下方。
要显示克隆功能,请使用以下示例数据集:
xxxxxxxxxx# zfs list -rt all camino/home/joeNAME USED AVAIL REFER MOUNTPOINTcamino/home/joe 108K 1.3G 87K /usr/home/joecamino/home/joe@plans 21K - 85.5K -camino/home/joe@backup 0K - 87K -克隆的一个典型用途是对特定的数据集进行实验,同时保留快照以防出现问题。由于快照无法更改,请创建快照的读/写克隆。在克隆中达到预期结果后,将克隆升级为数据集并删除旧文件系统。删除父数据集并不是绝对必要的,因为克隆和数据集可以共存而不会出现问题。
xxxxxxxxxx# 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/homeFilesystem Size Used Avail Capacity Mounted onusr/home/joe 1.3G 31k 1.3G 0% /usr/home/joeusr/home/joenew 1.3G 31k 1.3G 0% /usr/home/joenew创建克隆使其成为拍摄快照时数据集所处状态的精确副本。现在可以独立于其原始数据集更改克隆。两者之间的联系就是快照。ZFS在属性 origin 中记录此连接。使用 zfs promote 升级克隆会使克隆成为一个独立的数据集。这将删除 origin 属性的值,并将新独立的数据集与快照断开连接。这个例子说明了这一点:
xxxxxxxxxx# zfs get origin camino/home/joenewNAME PROPERTY VALUE SOURCEcamino/home/joenew origin camino/home/joe@backup -# zfs promote camino/home/joenew# zfs get origin camino/home/joenewNAME PROPERTY VALUE SOURCEcamino/home/joenew origin - -例如,在进行了一些更改(如将 loader.conf 复制到升级的克隆中)后,在这种情况下,旧目录将过时。相反,升级的克隆可以替换它。为此,首先使用 zfs destroy 销毁旧数据集,然后使用 zfs rename 将克隆重命名为旧数据集名称(或完全不同的名称)。
xxxxxxxxxx# 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/joebackup.txz loader.conf plans.txt# df -h /usr/homeFilesystem Size Used Avail Capacity Mounted onusr/home/joe 1.3G 128k 1.3G 0% /usr/home/joe克隆的快照现在是一个普通的数据集。它包含原始快照中的所有数据以及添加到其中的文件,如 loader.conf 。克隆在不同场景中为ZFS用户提供了有用的功能。例如,将jail作为包含不同已安装应用程序集的快照提供。用户可以克隆这些快照,并根据需要添加自己的应用程序。一旦对更改感到满意,就将克隆升级为完整的数据集,并将其提供给最终用户,让他们像处理真实数据集一样使用。这在提供这些jail时节省了时间和管理开销。
将单个池中的数据保存在一个位置会使其面临盗窃、自然或人为灾害等风险。对整个池进行定期备份至关重要。ZFS提供了一个内置的序列化功能,可以将数据的流表示发送到标准输出。使用此功能,可以将此数据存储在连接到本地系统的另一个池中,就像通过网络将其发送到另一个系统一样。快照是此复制的基础(请参阅【22.4.5. ZFS快照】一节)。用于复制数据的命令是 zfs send 和 zfs receive 。
这些示例显示了使用这两个池的ZFS复制:
xxxxxxxxxx# zpool listNAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOTbackup 960M 77K 896M - - 0% 0% 1.00x ONLINE -mypool 984M 43.7M 940M - - 0% 4% 1.00x ONLINE -名为 mypool 的池是定期写入和读取数据的主池。使用第二个备用池 backup ,以防主池不可用。请注意,ZFS不会自动完成此故障转移,但必须在需要时由系统管理员手动完成。使用快照提供要复制的一致文件系统版本。创建 mypool 的快照后,通过复制快照将其复制到 backup 池。这不包括自最近一次快照以来所做的更改。
xxxxxxxxxx# zfs snapshot mypool@backup1# zfs list -t snapshotNAME USED AVAIL REFER MOUNTPOINTmypool@backup1 0 - 43.6M -现在快照已经存在,使用 zfs send 创建一个表示快照内容的流。将此流存储为文件或在另一个池中接收它。将流写入标准输出,但重定向到文件或管道或出现错误:
xxxxxxxxxx# zfs send mypool@backup1Error: Stream can not be written to a terminal.You must redirect standard output.要使用 zfs send 备份数据集,请重定向到位于装载的备份池上的文件。确保池有足够的可用空间来容纳发送的快照的大小,这意味着快照中包含的数据,而不是对上一个快照的更改。
xxxxxxxxxx# zfs send mypool@backup1 > /backup/backup1# zpool listNAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOTbackup 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 send 和 zfs receive 组合在一起,将数据从一个池复制到另一个池。传输完成后,直接在接收池上使用数据。只能将数据集复制到空数据集。
xxxxxxxxxx# zfs snapshot mypool@replica1# zfs send -v mypool@replica1 | zfs receive backup/mypoolsend from @ to mypool@replica1 estimated size is 50.1Mtotal estimated size is 50.1MTIME SENT SNAPSHOT# zpool listNAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOTbackup 960M 63.7M 896M - - 0% 6% 1.00x ONLINE -mypool 984M 43.7M 940M - - 0% 4% 1.00x ONLINE -zfs send 还可以确定两个快照之间的差异,并发送两者之间的个体差异。这节省了磁盘空间和传输时间。例如:
xxxxxxxxxx# zfs snapshot mypool@replica2# zfs list -t snapshotNAME USED AVAIL REFER MOUNTPOINTmypool@replica1 5.72M - 43.6M -mypool@replica2 0 - 44.1M -# zpool listNAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOTbackup 960M 61.7M 898M - - 0% 6% 1.00x ONLINE -mypool 960M 50.2M 910M - - 0% 5% 1.00x ONLINE -创建第二个名为 replica2 的快照。第二个快照包含从现在到上一个快照 replica1 对文件系统所做的更改。使用 zfs send -i 并指示快照对会生成一个包含更改数据的增量副本流。如果接收端已存在初始快照,则此操作成功。
xxxxxxxxxx# zfs send -v -i mypool@replica1 mypool@replica2 | zfs receive /backup/mypoolsend from @replica1 to mypool@replica2 estimated size is 5.02Mtotal estimated size is 5.02MTIME SENT SNAPSHOT# zpool listNAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOTbackup 960M 80.8M 879M - - 0% 8% 1.00x ONLINE -mypool 960M 50.2M 910M - - 0% 5% 1.00x ONLINE -# zfs listNAME USED AVAIL REFER MOUNTPOINTbackup 55.4M 240G 152K /backupbackup/mypool 55.3M 240G 55.2M /backup/mypoolmypool 55.6M 11.6G 55.0M /mypool# zfs list -t snapshotNAME USED AVAIL REFER MOUNTPOINTbackup/mypool@replica1 104K - 50.2M -backup/mypool@replica2 0 - 55.2M -mypool@replica1 29.9K - 50.0M -mypool@replica2 0 - 55.0M -增量流复制了更改的数据,而不是整个 replica1 。单独发送差异所需的传输时间要短得多,并且通过每次不复制整个池来节省磁盘空间。当在慢速网络上复制或对每个传输字节收费时,这很有用。
新的文件系统 backup/mypool 可用于存储 mypool 池中的文件和数据。指定 -p 会复制数据集属性,包括压缩设置、配额和装载点。指定 -R 会复制数据集的所有子数据集及其属性。自动发送和接收,以在第二个池上创建定期备份。
通过网络发送流是保持远程备份的好方法,但它确实有一个缺点。通过网络链接发送的数据没有加密,允许任何人在发送用户不知情的情况下拦截流并将其转换回数据。当通过互联网将流发送到远程主机时,这是不可取的。使用SSH对通过网络连接发送的数据进行安全加密。由于ZFS需要从标准输出重定向流,因此通过SSH进行管道传输很容易。为了在传输和远程系统上对文件系统的内容进行加密,可以考虑使用PEFS。
更改一些设置并首先采取安全预防措施。这描述了 zfs send 操作所需的必要步骤;有关SSH的更多信息,请参阅【16.7. OpenSSH】。
按如下方式更改配置:
使用SSH密钥在发送和接收主机之间进行无密码SSH访问
ZFS需要 root 用户的权限来发送和接收流。这需要以 root 身份登录到接收系统。
默认情况下,安全原因阻止 root 登录。
使用ZFS委派系统允许每个系统上的非root用户执行相应的发送和接收操作。在发送系统上:
xxxxxxxxxx# zfs allow -u someuser send,snapshot mypool要挂载池,无特权用户必须拥有目录,普通用户需要装载文件系统的权限。
在接收系统上:
xxxxxxxxxx# sysctl vfs.usermount=1vfs.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无特权用户现在可以接收和挂载数据集,并将主数据集复制到远程系统:
xxxxxxxxxx% zfs snapshot -r mypool/home@monday% zfs send -R mypool/home@monday | ssh someuser@backuphost zfs recv -dvu recvpool/backup在池 mypool 上创建一个名为 monday 的文件系统数据集的递归快照。然后使用 zfs send -R 将数据集、所有子数据集、快照、克隆和设置包含在流中。通过SSH将输出传输到远程主机备份主机上等待的 zfs receive 。使用IP地址或完全限定域名是一种很好的做法。接收机器将数据写入 recvpool 池上的备份数据集。在 zfs recv 中添加 -d 会用快照的名称覆盖接收端的池名称。-u 导致文件系统在接收端无法挂载。使用 -v 可以显示有关传输的更多详细信息,包括经过的时间和传输的数据量。
使用数据集配额限制特定数据集消耗的空间量。引用配额的工作方式大致相同,但计算数据集本身使用的空间,不包括快照和子数据集。同样,使用用户和组配额来防止用户或组用完池或数据集中的所有空间。
以下示例假设用户已存在于系统中。在将用户添加到系统之前,请确保首先创建他们的主数据集,并将 mountpoint 设置为 /home/bob 。然后,创建用户并使主目录指向数据集的 mountpoint 位置。这将正确设置所有者和组权限,而不会遮挡可能存在的任何预先存在的主目录路径。
要为存储 /home/bob 强制10 GB的数据集配额:
xxxxxxxxxx# zfs set quota=10G storage/home/bob要为存储 /home/bob 强制10 GB的参考配额:
xxxxxxxxxx# zfs set refquota=10G storage/home/bob要删除存储 /home/bob 的10GB配额:
xxxxxxxxxx# zfs set quota=none storage/home/bob一般格式为 userquota@user=size ,用户名必须采用以下格式之一:
例如,要为名为 joe 的用户强制执行50GB的用户配额:
xxxxxxxxxx# zfs set userquota@joe=50G要删除任何配额,请执行以下操作:
xxxxxxxxxx# zfs set userquota@joe=nonexxxxxxxxxxzfs get all不显示用户配额属性。除非被授予 userquota 权限,否则非root用户无法看到其他用户的配额。拥有此权限的用户可以查看和设置每个人的配额。设置组配额的一般格式为:groupquota@group=size 。
要将组 firstgroup 的配额设置为50 GB,请使用:
xxxxxxxxxx# zfs set groupquota@firstgroup=50G要删除组 firstgroup 的配额,或确保未设置配额,请使用:
xxxxxxxxxx# zfs set groupquota@firstgroup=none与用户配额属性一样,非root用户可以看到与他们所属的组关联的配额。具有 groupquota 权限或 root 的用户可以查看和设置所有组的所有配额。
要显示文件系统或快照上每个用户使用的空间量以及任何配额,请使用 zfs userspace 。有关组信息,请使用 zfs groupspace 。有关支持的选项或如何单独显示特定选项的更多信息,请参阅 zfs(1) 。
特权用户和 root 可以使用以下命令列出 storage/home/bob 的配额:
xxxxxxxxxx# zfs get quota storage/home/bobReservations —— 预订保证了数据集上始终可用的空间量。保留的空间将不可用于任何其他数据集。此有用功能可确保为重要数据集或日志文件提供可用空间。
reservation 属性的一般格式是 reservation=size ,因此要在 storage/home/bob 上设置10GB的预留,请使用:
xxxxxxxxxx# zfs set reservation=10G storage/home/bob要清除任何预订:
xxxxxxxxxx# zfs set reservation=none storage/home/bob同样的原则也适用于设置参考预留的 refreservation 属性,其通用格式为 refreservation=size 。
此命令显示 storage/home/bob 上存在的任何保留或重新保留:
xxxxxxxxxx# zfs get reservation storage/home/bob# zfs get refreservation storage/home/bobZFS提供透明压缩。压缩在块级别写入的数据可以节省空间,还可以提高磁盘吞吐量。如果数据压缩25%,则压缩数据以与未压缩版本相同的速率写入磁盘,从而产生125%的有效写入速度。压缩也可以是重复数据删除的一个很好的替代方案,因为它不需要额外的内存。
ZFS提供了不同的压缩算法,每种算法都有不同的权衡。ZFS v5000中引入了LZ4压缩,可以压缩整个池,而不会像其他算法那样牺牲大量性能。LZ4的最大优点是早期中止(early abort)功能。如果LZ4在数据的头部部分没有实现至少12.5%的压缩,ZFS会在未压缩的情况下写入块,以避免浪费CPU周期来压缩已经压缩或不可压缩的数据。有关ZFS中可用的不同压缩算法的详细信息,请参阅术语部分中的compression条目。
管理员可以使用数据集属性查看压缩的有效性。
xxxxxxxxxx# zfs get used,compressratio,compression,logicalused mypool/compressed_datasetNAME PROPERTY VALUE SOURCEmypool/compressed_dataset used 449G -mypool/compressed_dataset compressratio 1.11x -mypool/compressed_dataset compression lz4 localmypool/compressed_dataset logicalused 496G -数据集使用了449 GB的空间(已使用的属性)。如果没有压缩,它将占用496 GB的空间( logicalused 属性)。这导致了1.11:1的压缩比。
当与用户配额结合使用时,压缩可能会产生意想不到的副作用。用户配额限制了压缩后用户在数据集上消耗的实际空间量。如果用户有10GB的配额,并写入10GB的可压缩数据,他们仍然可以存储更多的数据。如果他们以后用或多或少可压缩的数据更新文件,比如数据库,他们可用的空间量就会改变。这可能会导致一种奇怪的情况,即用户没有增加实际数据量(logicalused 属性),但压缩的变化导致他们达到了配额限制。
压缩可能会与备份发生类似的意外交互。配额通常用于限制数据存储,以确保有足够的可用备份空间。由于配额不考虑压缩,ZFS可能会写入比未压缩备份更多的数据。
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的级别需要大量内存来压缩每个块,RAM小于16GB的系统不应使用它们。ZFS也使用了一系列Zstd_fast_级别,这些级别相应地更快,但支持较低的压缩比。ZFS支持 zstd-fast-1 至 zstd-fast-10 、 zstd-fass-20 至 zstd-fast-100 ,增量为 10 ,以及 zstd-fast-500 和 zstd-fast-1000 ,它们提供最小的压缩,但提供高性能。
如果ZFS无法获得使用Zstd压缩块所需的内存,它将退回到存储未压缩的块。这不太可能发生,除非在内存受限的系统上Zstd的最高级别。ZFS统计自使用 kstat.ZFS.misc.zstd.compress_alloc_fail 加载ZFS模块以来发生这种情况的频率。
启用后,重复数据删除使用每个块的校验和来检测重复块。当一个新块是现有块的副本时,ZFS会向现有数据写入一个新的引用,而不是整个副本块。如果数据包含大量重复文件或重复信息,则可以节省大量空间。警告:重复数据删除需要大量内存,启用压缩可以节省大部分空间,而不会产生额外成本。
要激活重复数据消除,请在目标池上设置重复数据消除属性:
xxxxxxxxxx# zfs set dedup=on pool重复数据消除仅影响写入池的新数据。仅激活此选项不会对已写入池的数据进行重复数据消除。具有新激活的重复数据删除属性的池看起来像这样:
xxxxxxxxxx# zpool listNAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOTpool 2.84G 2.19M 2.83G - - 0% 0% 1.00x ONLINE -DEDUP 列显示了池的实际重复数据删除率。值 1.00x 表示数据尚未进行重复数据消除。下一个示例将一些系统二进制文件复制三次到上面创建的重复数据消除池上的不同目录中。
xxxxxxxxxx# for d in dir1 dir2 dir3; do> mkdir $d && cp -R /usr/bin $d &> done要观察冗余数据的重复数据删除,请使用:
xxxxxxxxxx# zpool listNAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOTpool 2.84G 20.9M 2.82G - - 0% 0% 3.00x ONLINE -DEDUP 列显示系数为 3.00x 。检测和删除数据副本会占用三分之一的空间。节省空间的潜力是巨大的,但代价是有足够的内存来跟踪重复数据消除的块。
当池中的数据不冗余时,重复数据删除并不总是有益的。ZFS可以通过模拟对现有池的重复数据删除来显示潜在的空间节省:
xxxxxxxxxx# zdb -S poolSimulated 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 是主要由压缩提供的较差的空间节省率。激活此池的重复数据删除功能不会节省任何空间,也不值得启用重复数据删除所需的内存量。使用公式 ratio=dedup * compress / copy ,系统管理员可以规划存储分配,决定工作负载是否包含足够的重复块来满足内存要求。如果数据具有合理的可压缩性,那么节省的空间可能会很好。好的做法是先启用压缩,因为压缩也可以大大提高性能。在节省可观且DDT有足够可用内存的情况下,启用重复数据删除。
使用 zfs jail 和相应的 jailed 属性将zfs数据集委托给jail。zfs jail jailid 将数据集附加到指定的jail,zfs unjail 将其分离。要从监狱内控制数据集,请设置 jailed 属性。ZFS禁止在主机上挂载被监禁的数据集,因为它可能有会危及主机安全的挂载点。
一个全面的权限委托系统允许无权限用户执行ZFS管理功能。例如,如果每个用户的主目录都是一个数据集,则用户需要权限来创建和销毁其主目录的快照。执行备份的用户可以获得使用复制功能的权限。ZFS允许使用统计脚本运行,仅访问所有用户的空间使用数据。委派权限的能力也是可能的。每个子命令和大多数属性都可以进行权限委派。
zfs allow someuser create mydataset 授予指定用户在所选父数据集下创建子数据集的权限。警告:创建新数据集需要挂载它。这需要将FreeBSD vfs.usermount sysctl(8) 设置为 1 ,以允许非root用户挂载文件系统。另一个旨在防止滥用的限制是:非root用户必须拥有装载文件系统的装载点。
zfs allow someuser allow mydataset 允许指定用户将他们对目标数据集或其子数据集的任何权限分配给其他用户。如果用户具有快照权限和允许权限,则该用户可以将快照权限授予其他用户。
调整可调参数,使ZFS在不同工作负载下表现最佳。
vfs.zfs.arc.max —— 从13.x开始(12.x为vfs.zfs.arc_max)
ARC的最大值。默认值为除1GB外的所有RAM,或所有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中适合的文件数据较少,则增加此值将提高性能。在运行时使用 /boot/loader.conf 或 /etc/sysctl.conf 中的sysctl(8)调整此值。
vfs.zfs.arc.min —— 从 13.x开始 (12.x为vfs.zfs.arc_min)
ARC的最小值。默认值为 vfs.zfs.ARC.meta_limit 的一半。调整此值以防止其他应用程序对整个ARC造成压力。在运行时使用 sysctl(8) 和 /boot/loder.conf 或 /etc/sysctl.conf 调整此值。
vfs.zfs.vdev.cache.size
为池中的每个设备保留作为缓存的预分配内存量。使用的内存总量将是该值乘以设备数量。在引导时和 /boot/loder.conf 中设置此值。
vfs.zfs.min_auto_ashift
在池创建时自动使用较低的 ashift (扇区大小)。该值是2的幂。默认值 9 表示 2^9=512 ,扇区大小为512字节。为了避免写入放大并获得最佳性能,请将此值设置为池中设备使用的最大扇区大小。
普通驱动器有4KB扇区。对这些驱动器使用默认的 ashift 9会导致这些设备上的写入放大。一次4KB写入中包含的数据改为八次512字节写入。ZFS在创建池时试图从所有设备读取本机扇区大小,但具有4KB扇区的驱动器报告说,为了兼容,它们的扇区为512字节。在创建池之前,将 vfs.zfs.min_auto_ashift 设置为 12 (2^12=4096)会强制zfs在这些驱动器上使用4KB块以获得最佳性能。
强制使用4KB块对于计划进行磁盘升级的池也很有用。未来的磁盘将使用4KB扇区,创建池后 ashft 值将无法更改。
在某些特定情况下,较小的512字节块大小可能更可取。当与512字节的磁盘一起用于数据库或用作虚拟机的存储时,在小随机读取期间的数据传输更少。当使用较小的ZFS记录大小时,这可以提供更好的性能。
vfs.zfs.prefetch_disable
禁用预取(prefetch)。值 0 启用,1 禁用。默认值为 0 ,除非系统的RAM小于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 Warmup Phase(Turbo预热阶段)可减少重新启动后空L2ARC的性能损失。随时使用 sysctl(8) 调整此值。
vfs.zfs.scrub_delay
scrub 期间每个I/O之间延迟的滴答(ticks)数。为了确保 scrub 不会干扰池的正常运行,如果发生任何其他I/O,擦除将在每个命令之间延迟。此值控制 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
在恢复过程中,每个I/O之间插入的延迟毫秒数。为确保 resilver 不会干扰池的正常运行,如果发生任何其他I/O,resilver将在每个命令之间延迟。此值控制由resilver生成的总IOPS(每秒I/O)的限制。ZFS通过 kern.hz 的值确定设置的粒度,默认值为每秒1000个滴答。更改此设置会导致不同的有效IOPS限制。默认值为2,导致限制为:1000滴答/秒/2=500 IOPS。如果另一个设备发生故障可能会导致池 Fault ,从而导致数据丢失,那么将池恢复到 Online 状态可能更重要。值为 0 将使resilver操作与其他操作具有相同的优先级,从而加快愈合过程。池中最近的其他活动限制了resilver的速度,由 vfs.zfs.scan_idle 决定。随时使用 sysctl(8) 调整此值。
vfs.zfs.scan_idle
在考虑池处于空闲状态之前,自上次操作以来的毫秒数。ZFS在池空闲时禁用 scrub 和 resilver 的速率限制。随时使用 sysctl(8) 调整此值。
vfs.zfs.txg.timeout
事务组之间的秒数上限。当前事务组写入池,如果自上一个事务组以来经过了这段时间,则会启动一个新的事务组。如果写入足够的数据,事务组可能会更早触发。默认值为5秒。较大的值可以通过延迟异步写入来提高读取性能,但这可能会导致写入事务组时性能不均衡。随时使用 sysctl(8) 调整此值。
ZFS提供的一些功能是内存密集型的,可能需要在RAM有限的系统上进行调优以提高效率。
作为较低的值,总系统内存应至少为1GB。推荐的RAM数量取决于池的大小以及ZFS使用的功能。一般经验法则是每1TB的存储需要1GB的RAM。如果使用重复数据消除功能,一般经验法则是每TB存储需要5 GB RAM进行重复数据消除。虽然一些用户使用RAM较少的ZFS,但负载过重的系统可能会因内存耗尽而死机。对于RAM要求低于推荐要求的系统,ZFS可能需要进一步调整。
由于i386™平台的地址空间限制,i386™架构上的ZFS用户必须将此选项添加到自定义内核配置文件中,重建内核,然后重新启动:
xxxxxxxxxxoptions KVA_PAGES=512这扩展了内核地址空间,允许 vm.kvm_size 可调参数推送超过1 GB的限制,或PAE的2 GB限制。要找到此选项的最合适值,请将所需的地址空间(以兆字节为单位)除以四。在这个例子中,512 代表2GB。
增加所有FreeBSD架构上的kmem地址空间。具有1GB物理内存的测试系统受益于将这些选项添加到 /boot/loader.conf ,然后重新启动:
xxxxxxxxxxvm.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 。
• OpenZFS • FreeBSD Wiki - ZFS Tuning • Calomel Blog - ZFS Raidz Performance, Capacity and Integrity
ZFS不仅仅是一个文件系统,它有着根本的不同。ZFS结合了文件系统和卷管理器的角色,使新的存储设备能够添加到活动系统中,并使该池中现有文件系统上的新空间立即可用。通过组合传统上独立的角色,ZFS能够克服以前阻碍RAID组增长的限制。vdev是池中的顶级设备,可以是简单的磁盘或RAID转换,如镜像或RAID-Z阵列。ZFS文件系统(称为数据集)每个都可以访问整个池的组合可用空间。池中已使用的块会减少每个文件系统的可用空间。这种方法避免了广泛分区的常见陷阱,即可用空间在分区之间变得碎片化。
pool
存储 pool 是ZFS最基本的构建块。池由一个或多个vdev组成,vdev是存储数据的底层设备。然后使用池创建一个或多个文件系统(数据集)或块设备(卷)。这些数据集和卷共享剩余的可用空间池。每个池都由名称和GUID唯一标识。池上的ZFS版本号决定了可用的功能。
vdev 类型
池由一个或多个vdev组成,vdev本身是一个磁盘或一组磁盘,转换为RAID。当使用大量vdev时,ZFS会在vdev之间传播数据,以提高性能并最大限度地利用可用空间。所有vdev的大小必须至少为128 MB。
Disk
最基本的vdev类型是标准块设备。这可以是整个磁盘(如 /dev/ada0 或 /dev/da0 )或分区( /dev/ada0p3 )。在FreeBSD上,使用分区而不是整个磁盘不会造成性能损失。这与Solaris文档中的建议不同。
xxxxxxxxxx强烈建议不要将整个磁盘用作可引导池的一部分,因为这可能会使池无法引导。同样,您不应该将整个磁盘用作镜像或RAID-Z vdev的一部分。在启动时可靠地确定未分区磁盘的大小是不可能的,也没有地方放启动代码。File
常规文件可以组成ZFS池,这对测试和实验很有用。使用文件的完整路径作为 zpool create 中的设备路径。
Mirror
创建镜像时,指定 mirror 关键字,后跟镜像的成员设备列表。镜像由两个或多个设备组成,将所有数据写入所有成员设备。镜像vdev将保存与其最小成员一样多的数据。镜像vdev可以承受除一个成员外的所有成员的故障,而不会丢失任何数据。
xxxxxxxxxx要随时将常规单磁盘vdev升级为镜像vdev,请使用zpool attach。RAID-Z
Spare
ZFS有一种特殊的伪vdev类型,用于跟踪可用的热备盘。请注意,安装的热备盘不会自动部署;手动配置它们,使用 zfs -replace 替换故障设备。
Log
ZFS日志设备,也称为ZFS意图日志(ZFS Intent Log,ZIL),将意图日志从常规池设备移动到专用设备,通常是SSD。拥有专用日志设备可以提高数据库等具有大量同步写入的应用程序的性能。日志设备的镜像是可能的,但不支持RAID-Z。如果使用大量日志设备,写入将在它们之间进行负载平衡。
Cache
将缓存vdev添加到池中会将缓存的存储添加到L2ARC。镜像缓存设备是不可能的。由于缓存设备只存储现有数据的新副本,因此没有数据丢失的风险。
Transaction Group (TXG)
事务组是ZFS组将更改块在一起并将其写入池的方式。事务组是ZFS用来确保一致性的原子单位。ZFS为每个事务组分配一个唯一的64位连续标识符。一次最多可以有三个活动事务组,这三个状态各一个:
Open
一个新的事务组在打开状态下开始并接受新的写入。始终有一个事务组处于打开状态,但如果达到限制,该事务组可能会拒绝新的写入。一旦打开的事务组达到限制,或达到 vfs.zfs.txg.timeout ,事务组将进入下一个状态。
Quiescing
一种短状态,允许任何挂起的操作完成,而不会阻止创建新的打开的事务组。一旦组中的所有事务都完成,事务组将进入最终状态。
Syncing
将事务组中的所有数据写入稳定存储。这个过程反过来会改变ZFS也会写入稳定存储的其他数据,如元数据和空间图。同步过程涉及几次传递。在第一个也是最大的数据块上,所有更改的数据块;接下来是元数据,可能需要几次才能完成。由于为数据块分配空间会生成新的元数据,因此在不使用任何新空间的传递完成之前,同步状态无法完成。同步状态也是同步任务完成的地方。同步任务是管理操作,例如创建或销毁完成uberblock更改的快照和数据集。
一旦同步状态完成,处于静止状态的事务组将进入同步状态。所有管理功能,例如作为事务组的一部分写入 snapshot 。ZFS将创建的同步任务添加到打开的事务组中,该组会尽快进入同步状态,以减少管理命令的延迟。
Adaptive Replacement Cache (ARC)
ZFS使用自适应替换缓存(Adaptive Replacement Cache,ARC),而不是更传统的最近最少使用(Least Recently Used,LRU)缓存。LRU缓存是缓存中一个简单的项目列表,按最近使用对象的方式排序,将新项目添加到列表的开头。当缓存已满时,从列表末尾删除项目会为更多活动对象腾出空间。ARC由四个列表组成;最近使用(Most Recently Used,MRU)和最频繁使用(Most Frequently Used,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_bost 在“Turbo预热阶段”(写增强)增加了这一限制。
ZIL
ZIL通过使用比主存储池中使用的存储设备更快的SSD等存储设备来加速同步事务。当应用程序请求同步写入时(保证数据存储到磁盘,而不仅仅是缓存以供以后写入),将数据写入更快的ZIL存储,然后稍后将其刷新到常规磁盘,可以大大降低延迟并提高性能。像数据库这样的同步工作负载将仅从ZIL中获利。常规异步写入(如复制文件)根本不会使用ZIL。
Copy-On-Write
与传统的文件系统不同,ZFS写入不同的块,而不是在原地覆盖旧数据。完成此写入操作后,元数据将更新以指向新位置。当发生削写(shorn write,在写入文件的过程中系统崩溃或断电)时,文件的整个原始内容仍然可用,ZFS将丢弃未完成的写入。这也意味着ZFS在意外关机后不需要 fsck(8) 。
Dataset
Dataset —— 数据集是ZFS文件系统、卷、快照或克隆的通用术语。每个数据集都有一个 poolname/path@snapshot 格式的唯一名称。池的根也是一个数据集。子数据集具有分层名称,如目录。例如,主数据集 mypool/home 是 mypool 的子数据集,并继承了 mypool 的属性。通过创建 mypool/home/user 进一步扩展它。此孙数据集将继承父级和祖父母的属性。设置子对象的属性以覆盖从父对象和祖父母继承的默认值。数据集及其子数据集的管理可以委托。
文件系统
ZFS数据集最常用作文件系统。与大多数其他文件系统一样,ZFS文件系统挂载在系统目录层次结构中的某个位置,包含自己的文件和目录,以及权限、标志和其他元数据。
Volume
ZFS还可以创建卷,这些卷显示为磁盘设备。卷具有许多与数据集相同的功能,包括写时复制、快照、克隆和校验和。卷对于在ZFS之上运行其他文件系统格式非常有用,例如UFS虚拟化或导出iSCSI扩展。
快照
ZFS的写时复制(COW)设计允许使用任意名称进行几乎即时、一致的快照。在拍摄数据集的快照或包含所有子数据集的父数据集的递归快照后,新数据会进入新块,但不会将旧块回收为可用空间。快照包含原始文件系统版本,实时文件系统包含自不使用其他空间拍摄快照以来所做的任何更改。写入实时文件系统的新数据使用新块来存储这些数据。当块不再在实时文件系统中使用,而是仅在快照中使用时,快照将增长。以只读方式装载这些快照允许恢复以前的文件版本。可以将实时文件系统rollback 到特定快照,撤消拍摄快照后发生的任何更改。池中的每个块都有一个引用计数器,用于跟踪使用该块的快照、克隆、数据集或卷。随着文件和快照被删除,引用计数会减少,在不再引用块时回收可用空间。用 hold 标记快照会导致任何销毁快照的尝试都会返回 EBUSY 错误。每个快照都可以有一个唯一的名称。 release 命令会删除保留,以便删除快照。快照、克隆和回滚可以在卷上工作,但独立挂载则不行。
克隆
也可以克隆快照。克隆是快照的可写版本,允许文件系统分叉为新的数据集。与快照一样,克隆最初不会占用新的空间。当写入克隆的新数据使用新块时,克隆的大小会增长。当克隆的文件系统或卷中的块被覆盖时,上一个块的引用计数会减少。由于克隆依赖于快照,因此无法删除克隆所基于的快照。快照是父快照,克隆是子快照。可以升级克隆,颠倒这种依赖关系,使克隆成为父级,前一个父级成为子级。此操作不需要新的空间。由于父级和子级使用的空间量颠倒,可能会影响现有的配额和保留。
Checksum
每个块也会进行校验和。使用的校验和算法是每个数据集的属性,请参阅 set 。读取时,每个块的校验和都会被透明地验证,使ZFS能够检测到无声的损坏。如果读取的数据与预期的校验和不匹配,ZFS将尝试从任何可用的冗余中恢复数据,如镜像或RAID-Z。通过 scrub 触发所有校验和的验证。校验和算法包括:
fletcher2 、 fletcher4 、 sha256。
fletcher 算法更快,但 sha256 是一个强大的加密哈希,以牺牲一些性能为代价,冲突的可能性要低得多。停用校验和是可能的,但强烈建议不要这样做。
压缩
每个数据集都有一个 compression (压缩)属性,默认为关闭。将此属性设置为可用的压缩算法。这会导致写入数据集的所有新数据被压缩。除了减少使用的空间外,读写吞吐量通常会增加,因为需要读写的块更少。
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 到最高压缩级别 gzip 9 。这使管理员可以控制用多少CPU时间换取节省的磁盘空间。
ZLE
Zero Length Encoding,零长度编码是一种特殊的压缩算法,仅压缩连续的零序列。当数据集包含大块的零时,这种压缩算法很有用。
Copies
当设置为大于1的值时, copies 属性指示ZFS维护 crossref:zfs[zfs-term-filesystem,file system] 或卷中每个块的副本。在重要数据集上设置此属性可以提供额外的冗余,从中恢复与其校验和不匹配的块。在没有冗余的池中,复制功能是单一形式的冗余。复制功能可以从单个坏扇区或其他形式的轻微损坏中恢复,但它并不能保护池免受整个磁盘的丢失。
去重
校验和可以在写入数据时检测重复块。通过重复数据删除,现有相同块的引用计数会增加,从而节省存储空间。ZFS在内存中保留一个重复数据删除表(deduplication table,DDT)来检测重复块。该表包含唯一校验和列表、这些块的位置和引用计数。在写入新数据时,ZFS计算校验和并将其与列表进行比较。当找到匹配项时,它会使用现有块。使用带有重复数据删除的SHA256校验和算法可以提供安全的加密哈希。重复数据删除是可调的。如果设置了 dedup 为 on ,则匹配的校验和意味着数据是相同的。通过设置 dedup 为 verify ,ZFS对数据进行逐字节检查,确保它们实际上是相同的。如果数据不相同,ZFS将注意到哈希冲突,并分别存储这两个块。由于DDT必须存储每个唯一块的哈希值,因此它消耗了大量内存。一般经验法则是每1TB重复数据删除5-6GB ram)。在没有足够RAM将整个DDT保存在内存中的情况下,性能将受到很大影响,因为DDT必须在写入每个新块之前从磁盘读取。重复数据删除可以使用L2ARC来存储DDT,在快速系统内存和较慢的磁盘之间提供一个中间地带。考虑改用压缩,这通常可以在不增加内存的情况下节省几乎同样多的空间。
Scrub
ZFS没有像 fsck(8) 那样进行一致性检查,而是使用了 scrub 。scrub 读取存储在池中的所有数据块,并根据元数据中存储的已知良好校验和验证它们的校验和。定期检查存储在池中的所有数据,确保在需要之前恢复任何损坏的块。不干净的停机后不需要擦洗,但良好的做法是至少每三个月一次。ZFS在正常使用期间验证每个块的校验和,但擦除确保检查即使是不常用的块是否存在无声损坏。ZFS提高了档案存储情况下的数据安全性。使用 vfs.zfs.scrub_delay 调整 scrub 的相对优先级,以防止清理降低池上其他工作负载的性能。
数据集配额
ZFS提供快速准确的数据集、用户和组空间统计以及配额和空间预留。这为管理员提供了对空间分配的细粒度控制,并允许为关键文件系统保留空间。
ZFS支持不同类型的配额:数据集配额、引用配额(refquota)、用户配额和组配额。
配额限制了数据集及其后代的总大小,包括数据集的快照、子数据集和这些数据集的Snapshot。
xxxxxxxxxx卷不支持配额,因为volsize属性充当隐式配额。引用配额 —— Reference Quota
引用配额通过强制执行硬限制来限制数据集可以消耗的空间量。此硬限制包括数据集单独引用的空间,不包括子体(如文件系统或快照)使用的空间。
用户配额 —— User Quota
用户配额有助于限制指定用户使用的空间量。
组配额 —— Group Quota
组配额限制了指定组可以使用的空间量。
数据集预留 —— Dataset Reservation
reservation 属性可以保证特定数据集及其后代有足够的空间。这意味着在 storage/home/bob 上设置10GB的保留可以防止其他数据集用完所有可用空间,为此数据集保留至少10GB的空间。与常规 refreservation 不同,快照和后代使用的空间不计入保留。例如,如果对 storage/home/bob 进行快照,则除了 refreservation 之外,还必须有足够的磁盘空间才能使操作成功。主数据集的后代不计入 refreservation ,因此不会占用空间集。
在规划和测试新系统中磁盘空间分配的适用性,或确保文件系统上有足够的空间用于音频日志或系统恢复过程和文件等情况下,任何类型的保留都是有用的。
参考预订 —— Reference Reservation
refreservation 属性可以保证特定数据集(不包括其后代)的使用空间量。这意味着在 storage/home/bob 上设置10 GB的保留,另一个数据集会尝试使用可用空间,为此数据集保留至少10 GB的空间。与常规 reservation 相比,快照和后代数据集使用的空间不计入保留。例如,如果对 storage/home/bob 进行快照,则除了 refreservation 之外,还必须有足够的磁盘空间才能使操作成功。主数据集的后代不计入 refreservation ,因此不会占用空间集。
Resilver
更换故障磁盘时,ZFS必须用丢失的数据填充新磁盘。重新填充(reslivering)是使用分布在剩余驱动器上的奇偶校验信息来计算丢失的数据并将其写入新驱动器的过程。
Online
处于 Online 状态的池或vdev的成员设备已连接并完全运行。处于 Online 状态的单个设备正在运行。
Offline
如果存在足够的冗余,管理员会将单个设备置于 Offline 状态,以避免将池或vdev置于 Faulted 状态。管理员可以选择使磁盘脱机以准备更换,或者使其更容易识别。
Degraded
处于 Degraded 状态的池或vdev有一个或多个磁盘消失或发生故障。池仍然可用,但如果其他设备发生故障,池可能会变得不可恢复。在重新连接的设备或新设备完成Resilver 过程后,重新连接丢失的设备或更换故障磁盘将使池恢复到 Online 状态。
Faulted
处于 Faulted 状态的池或vdev不再运行。访问数据已不再可能。当丢失或故障设备的数量超过vdev中的冗余级别时,池或vdev进入 Faulted 状态。如果重新连接丢失的设备,池将返回 Online 状态。冗余不足,无法补偿故障磁盘的数量。磁盘池内容丢失,需要从备份中恢复。