Oracle Solaris ZFS 管理指南

第 7 章 使用 Oracle Solaris ZFS 快照和克隆

本章介绍如何创建和管理 Oracle Solaris ZFS 快照和克隆。此外还提供了有关保存快照的信息。

本章包含以下各节:

ZFS 快照概述

快照是文件系统或卷的只读副本。快照几乎可以即时创建,而且最初不占用池中的其他磁盘空间。但是,当活动数据集中的数据发生更改时,快照通过继续引用旧数据占用磁盘空间,从而阻止释放磁盘空间。

ZFS 快照具有以下特征:

无法直接访问卷的快照,但是可以对它们执行克隆、备份、回滚等操作。有关备份 ZFS 快照的信息,请参见发送和接收 ZFS 数据

创建和销毁 ZFS 快照

快照是使用 zfs snapshot 命令创建的,该命令将要创建的快照的名称用作其唯一参数。快照名称按如下方式指定:


filesystem@snapname
volume@snapname

快照名称必须满足ZFS 组件命名要求中所述的命名要求。

在以下示例中,将创建 tank/home/ahrens 的快照,其名称为 friday


# zfs snapshot tank/home/ahrens@friday

通过使用 -r 选项可为所有后代文件系统创建快照。例如:


# zfs snapshot -r tank/home@now
# zfs list -t snapshot
NAME                       USED  AVAIL  REFER  MOUNTPOINT
rpool/ROOT/zfs2BE@zfs2BE  78.3M      -  4.53G  -
tank/home@now                 0      -    26K  -
tank/home/ahrens@now          0      -   259M  -
tank/home/anne@now            0      -   156M  -
tank/home/bob@now             0      -   156M  -
tank/home/cindys@now          0      -   104M  -

快照没有可修改的属性。也不能将数据集属性应用于快照。例如:


# zfs set compression=on tank/home/ahrens@now
cannot set compression property for 'tank/home/ahrens@now': snapshot
properties cannot be modified

使用 zfs destroy 命令可以销毁快照。例如:


# zfs destroy tank/home/ahrens@now

如果数据集存在快照,则不能销毁该数据集。例如:


# zfs destroy tank/home/ahrens
cannot destroy 'tank/home/ahrens': filesystem has children
use '-r' to destroy the following datasets:
tank/home/ahrens@tuesday
tank/home/ahrens@wednesday
tank/home/ahrens@thursday

此外,如果已从快照创建克隆,则必须先销毁克隆,才能销毁快照。

有关 destroy 子命令的更多信息,请参见销毁 ZFS 文件系统

保持 ZFS 快照

如果存在不同的原子快照策略,导致旧的快照由于不再存在于发送侧而被 zfs receive 不小心销毁,则可能需要考虑使用本 Solaris 发行版中的快照保持功能。

保持快照可以防止它被销毁。此外,当一个带有克隆的快照等待删除最后一个克隆时,该功能允许使用 zfs destroy - d 命令删除该快照。每个快照都有一个关联的用户引用计数,其初始值为 0。对一个快照设置一个保持时,此计数递增 1;释放一个保持时,此计数递减 1。

在先前的 Solaris 发行版中,只有在快照无克隆时,才能使用 zfs destroy 命令销毁快照。在本 Solaris 发行版中,快照同样必须有一个用户引用计数。

可以保持一个快照或一组快照。例如,以下语法对 tank/home/cindys/snap@1 设置一个保持标志 keep


# zfs hold keep tank/home/cindys@snap1

可以使用 -r 选项递归保持所有后代文件系统的快照。例如:


# zfs snapshot -r tank/home@now
# zfs hold -r keep tank/home@now

此语法向给定的快照或快照集添加一个引用 keep。每个快照都有其自己的标志名称空间,保持标志在该空间内必须是唯一的。如果一个快照上存在一个保持,尝试使用 zfs destroy 命令销毁受保持的快照将失败。例如:


# zfs destroy tank/home/cindys@snap1
cannot destroy 'tank/home/cindys@snap1': dataset is busy

要销毁受保持的快照,须使用 -d 选项。例如:


# zfs destroy -d tank/home/cindys@snap1

使用 zfs holds 命令显示受保持的快照列表。例如:


# zfs holds tank/home@now
NAME           TAG   TIMESTAMP                 
tank/home@now  keep  Thu Jul 15 11:25:39 2010  

# zfs holds -r tank/home@now
NAME                  TAG   TIMESTAMP                 
tank/home/cindys@now  keep  Thu Jul 15 11:25:39 2010  
tank/home/mark@now    keep  Thu Jul 15 11:25:39 2010  
tank/home@now         keep  Thu Jul 15 11:25:39 2010  

可以使用 zfs release 命令释放对一个快照或一组快照的保持。例如:


# zfs release -r keep tank/home@now

释放快照后,可以使用 zfs destroy 命令销毁快照。例如:


# zfs destroy -r tank/home@now

有两个新属性用来表示快照保持信息:

重命名 ZFS 快照

可以重命名快照,但是必须在从中创建它们的池和数据集中对它们进行重命名。例如:


# zfs rename tank/home/cindys@083006 tank/home/cindys@today

此外,以下快捷方式语法等效于以上的语法:


# zfs rename tank/home/cindys@083006 today

不支持以下快照 rename 操作,因为目标池和文件系统名称与从中创建快照的池和文件系统不同:


# zfs rename tank/home/cindys@today pool/home/cindys@saturday
cannot rename to 'pool/home/cindys@today': snapshots must be part of same 
dataset

可以使用 zfs rename -r 命令以递归方式重命名快照。例如:


# zfs list
NAME                         USED  AVAIL  REFER  MOUNTPOINT
users                        270K  16.5G    22K  /users
users/home                    76K  16.5G    22K  /users/home
users/home@yesterday            0      -    22K  -
users/home/markm              18K  16.5G    18K  /users/home/markm
users/home/markm@yesterday      0      -    18K  -
users/home/marks              18K  16.5G    18K  /users/home/marks
users/home/marks@yesterday      0      -    18K  -
users/home/neil               18K  16.5G    18K  /users/home/neil
users/home/neil@yesterday       0      -    18K  -
# zfs rename -r users/home@yesterday @2daysago
# zfs list -r users/home
NAME                        USED  AVAIL  REFER  MOUNTPOINT
users/home                   76K  16.5G    22K  /users/home
users/home@2daysago            0      -    22K  -
users/home/markm             18K  16.5G    18K  /users/home/markm
users/home/markm@2daysago      0      -    18K  -
users/home/marks             18K  16.5G    18K  /users/home/marks
users/home/marks@2daysago      0      -    18K  -
users/home/neil              18K  16.5G    18K  /users/home/neil
users/home/neil@2daysago       0      -    18K  -

显示和访问 ZFS 快照

您可以通过 listsnapshots 池属性启用或禁用 zfs list 输出中的快照列表显示。缺省情况下,此属性处于启用状态。

如果禁用了此属性,则可以使用 zfs list -t snapshot 命令来显示快照信息。 或者,启用 listsnapshots 池属性。例如:


# zpool get listsnapshots tank
NAME  PROPERTY       VALUE      SOURCE
tank  listsnapshots  on        default
# zpool set listsnapshots=off tank
# zpool get listsnapshots tank
NAME  PROPERTY       VALUE      SOURCE
tank  listsnapshots  off         local

在文件系统的根的 .zfs/snapshot 目录中,可以访问文件系统的快照。例如,如果在 /home/ahrens 上挂载 tank/home/ahrens,则可以在 /home/ahrens/.zfs/snapshot/thursday 目录中访问 tank/home/ahrens@thursday 快照数据。


# ls /tank/home/ahrens/.zfs/snapshot
tuesday wednesday thursday

可以列出快照,如下所示:


# zfs list -t snapshot
NAME                        USED  AVAIL  REFER  MOUNTPOINT
pool/home/anne@monday          0      -   780K  -
pool/home/bob@monday           0      -  1.01M  -
tank/home/ahrens@tuesday   8.50K      -   780K  -
tank/home/ahrens@wednesday 8.50K      -  1.01M  -
tank/home/ahrens@thursday      0      -  1.77M  -
tank/home/cindys@today     8.50K      -   524K  -

可以列出为特定文件系统创建的快照,如下所示:


# zfs list -r -t snapshot -o name,creation tank/home
NAME                  CREATION
tank/home@now         Wed Jun 30 16:16 2010
tank/home/ahrens@now  Wed Jun 30 16:16 2010
tank/home/anne@now    Wed Jun 30 16:16 2010
tank/home/bob@now     Wed Jun 30 16:16 2010
tank/home/cindys@now  Wed Jun 30 16:16 2010

ZFS 快照的磁盘空间记帐

创建快照时,最初在快照和文件系统之间共享其磁盘空间,还可能与以前的快照共享其空间。在文件系统发生更改时,以前共享的磁盘空间将变为该快照专用的空间,因此会将该空间算入快照的 used 属性。此外,删除快照可增加其他快照专用(使用)的磁盘空间量。

创建快照时,快照的空间 referenced 属性值与文件系统的相同。

可以找到有关 used 属性值如何被占用的附加信息。新的只读文件系统属性说明克隆、文件系统和卷的磁盘空间使用情况。例如:


$ zfs list -o space
# zfs list -ro space tank/home
NAME                  AVAIL   USED  USEDSNAP  USEDDS  USEDREFRESERV  USEDCHILD
tank/home             66.3G   675M         0     26K              0       675M
tank/home@now             -      0         -       -              -          -
tank/home/ahrens      66.3G   259M         0    259M              0          0
tank/home/ahrens@now      -      0         -       -              -          -
tank/home/anne        66.3G   156M         0    156M              0          0
tank/home/anne@now        -      0         -       -              -          -
tank/home/bob         66.3G   156M         0    156M              0          0
tank/home/bob@now         -      0         -       -              -          -
tank/home/cindys      66.3G   104M         0    104M              0          0
tank/home/cindys@now      -      0         -       -              -          -

有关这些属性的说明,请参见表 6–1

回滚 ZFS 快照

可以使用 zfs rollback 命令放弃自特定快照创建以来对文件系统所做的全部更改。文件系统恢复到创建快照时的状态。缺省情况下,该命令无法回滚到除最新快照以外的快照。

要回滚到早期快照,必须销毁所有的中间快照。可以通过指定 -r 选项销毁早期的快照。

如果存在任何中间快照的克隆,则还必须指定 -R 选项以销毁克隆。


注 –

如果要回滚的文件系统当前为挂载状态,则会取消挂载并重新挂载。如果无法取消挂载该文件系统,则回滚将失败。-f 选项可强制取消挂载文件系统(如有必要)。


在以下示例中,会将 tank/home/ahrens 文件系统回滚到 tuesday 快照:


# zfs rollback tank/home/ahrens@tuesday
cannot rollback to 'tank/home/ahrens@tuesday': more recent snapshots exist
use '-r' to force deletion of the following snapshots:
tank/home/ahrens@wednesday
tank/home/ahrens@thursday
# zfs rollback -r tank/home/ahrens@tuesday

在本示例中,因为已回滚到以前的 tuesday 快照,所以销毁了 wednesdaythursday 快照。


# zfs list -r -t snapshot -o name,creation tank/home/ahrens
NAME                  CREATION
tank/home/ahrens@now  Wed Jun 30 16:16 2010

ZFS 克隆概述

克隆是可写入的卷或文件系统,其初始内容与从中创建它的数据集的内容相同。与快照一样,创建克隆几乎是即时的,而且最初不占用其他磁盘空间。此外,还可以创建克隆的快照。

克隆只能从快照创建。克隆快照时,会在克隆和快照之间建立隐式相关性。即使克隆是在数据集分层结构中的某个其他位置创建的,但只要克隆存在,就无法销毁原始快照。origin 属性显示此相关性,而 zfs destroy 命令会列出任何此类相关性(如果存在)。

克隆不继承从其中创建它的数据集的属性。使用 zfs getzfs set 命令,可以查看和更改克隆数据集的属性。有关设置 ZFS 数据集属性的更多信息,请参见设置 ZFS 属性

由于克隆最初与原始快照共享其所有磁盘空间,因此其 used 属性值最初为零。随着不断对克隆进行更改,它使用的磁盘空间将越来越多。原始快照的 used 属性不包括克隆所占用的磁盘空间。

创建 ZFS 克隆

要创建克隆,请使用 zfs clone 命令,指定从中创建克隆的快照以及新文件系统或卷的名称。新文件系统或卷可以位于 ZFS 分层结构中的任意位置。新数据集与从其中创建克隆的快照属同一类型(例如文件系统或卷)。不能在原始文件系统快照所在池以外的池中创建该文件系统的克隆。

在以下示例中,将创建一个名为 tank/home/ahrens/bug123 的新克隆,其初始内容与快照 tank/ws/gate@yesterday 的内容相同:


# zfs snapshot tank/ws/gate@yesterday
# zfs clone tank/ws/gate@yesterday tank/home/ahrens/bug123

在以下示例中,将从 projects/newproject@today 快照为临时用户创建克隆工作区 projects/teamA/tempuser。然后,在克隆工作区上设置属性。


# zfs snapshot projects/newproject@today
# zfs clone projects/newproject@today projects/teamA/tempuser
# zfs set sharenfs=on projects/teamA/tempuser
# zfs set quota=5G projects/teamA/tempuser

销毁 ZFS 克隆

使用 zfs destroy 命令可以销毁 ZFS 克隆。例如:


# zfs destroy tank/home/ahrens/bug123

必须先销毁克隆,才能销毁父快照。

使用 ZFS 克隆替换 ZFS 文件系统

借助 zfs promote 命令可以用活动的 ZFS 文件系统的克隆来替换该文件系统。利用此功能可以克隆并替换文件系统,使文件系统变为指定文件系统的克隆。此外,通过此功能还可以销毁最初创建克隆所基于的文件系统。如果没有克隆提升 (clone promotion) 功能,就无法销毁活动克隆的源文件系统。有关销毁克隆的更多信息,请参见销毁 ZFS 克隆

在以下示例中,对 tank/test/productA 文件系统进行了克隆,然后克隆文件系统 tank/test/productAbeta 成为原始 tank/test/productA 文件系统。


# zfs create tank/test
# zfs create tank/test/productA
# zfs snapshot tank/test/productA@today
# zfs clone tank/test/productA@today tank/test/productAbeta
# zfs list -r tank/test
NAME                       USED  AVAIL  REFER  MOUNTPOINT
tank/test                  104M  66.2G    23K  /tank/test
tank/test/productA         104M  66.2G   104M  /tank/test/productA
tank/test/productA@today      0      -   104M  -
tank/test/productAbeta        0  66.2G   104M  /tank/test/productAbeta
# zfs promote tank/test/productAbeta
# zfs list -r tank/test
NAME                           USED  AVAIL  REFER  MOUNTPOINT
tank/test                      104M  66.2G    24K  /tank/test
tank/test/productA                0  66.2G   104M  /tank/test/productA
tank/test/productAbeta         104M  66.2G   104M  /tank/test/productAbeta
tank/test/productAbeta@today      0      -   104M  -

在此 zfs list 输出中,注意源 productA 文件系统的磁盘空间记帐信息已被 productAbeta 文件系统取代。

可以通过重命名文件系统完成克隆替换过程。例如:


# zfs rename tank/test/productA tank/test/productAlegacy
# zfs rename tank/test/productAbeta tank/test/productA
# zfs list -r tank/test

或者,也可以删除传统的文件系统。例如:


# zfs destroy tank/test/productAlegacy

发送和接收 ZFS 数据

zfs send 命令创建写入标准输出的快照流表示。缺省情况下,生成完整的流。可以将输出重定向到文件或其他系统。zfs receive 命令创建其内容在标准输入提供的流中指定的快照。如果接收了完整的流,那么同时会创建一个新文件系统。可通过这些命令来发送 ZFS 快照数据并接收 ZFS 快照数据和文件系统。请参见下一节中的示例。

以下是用于保存 ZFS 数据的备份解决方案:

使用其他备份产品保存 ZFS 数据

zfs sendzfs receive 命令外,还可以使用归档实用程序(如 tarcpio 命令)保存 ZFS 文件。这些实用程序可以保存和恢复 ZFS 文件属性和 ACL。请选中 tarcpio 命令的适当选项。

有关 ZFS 问题和第三方备份产品的最新信息,请参见 Solaris 10 发行说明或位于以下位置的 ZFS 常见问题解答:

http://hub.opensolaris.org/bin/view/Community+Group+zfs/faq/#backupsoftware

发送 ZFS 快照

可以使用 zfs send 命令来发送某个快照流的副本,并在同一系统的另一个池中或用于存储备份数据的不同系统上的另一个池中接收快照流。例如,要将不同池上的快照流发送到同一系统,请使用类似如下的语法:


# zfs send tank/data@snap1 | zfs recv spool/ds01

可以将 zfs recv 用作 zfs receive 命令的别名。

如果要将快照流发送到不同的系统,请通过 ssh 命令传输 zfs send 输出。例如:


host1# zfs send tank/dana@snap1 | ssh host2 zfs recv newtank/dana

发送完整的流时,目标文件系统必须不能存在。

使用 zfs send -i 选项可以发送增量数据。例如:


host1# zfs send -i tank/dana@snap1 tank/dana@snap2 | ssh host2 zfs recv newtank/dana

请注意,第一个参数 (snap1) 是较早的快照,第二个参数 (snap2) 是较晚的快照。这种情况下,newtank/dana 文件系统必须已经存在,增量接收才能成功。

可将增量 snap1 源指定为快照名称的最后一个组成部分。此快捷方式意味着只需在 @ 符号后指定 snap1 的名称,假定它与 snap2 都来自同一文件系统。例如:


host1# zfs send -i snap1 tank/dana@snap2 > ssh host2 zfs recv newtank/dana

这一快捷方式语法等效于上例中的增量语法。

尝试从其他文件系统 snapshot1 生成增量流时,将显示以下消息:


cannot send 'pool/fs@name': not an earlier snapshot from the same fs

如果需要存储许多副本,可以考虑使用 gzip 命令压缩 ZFS 快照流表示。例如:


# zfs send pool/fs@snap | gzip > backupfile.gz

接收 ZFS 快照

接收文件系统快照时,请牢记以下要点:

例如:


# zfs send tank/gozer@0830 > /bkups/gozer.083006
# zfs receive tank/gozer2@today < /bkups/gozer.083006
# zfs rename tank/gozer tank/gozer.old
# zfs rename tank/gozer2 tank/gozer

如果对目标文件系统进行更改并且要再次以增量方式发送快照,则必须先回滚接收文件系统。

请参考以下示例。首先更改文件系统,如下所示:


host2# rm newtank/dana/file.1

然后以增量方式发送 tank/dana@snap3。但是,要接收新的增量快照,首先必须回滚接收文件系统。或者,使用 -F 选项可以取消回滚步骤。例如:


host1# zfs send -i tank/dana@snap2 tank/dana@snap3 | ssh host2 zfs recv -F newtank/dana

接收增量快照时,目标文件系统必须已存在。

如果对文件系统进行更改,但不回滚接收文件系统以接收新的增量快照,或者不使用 -F 选项,则会看到类似以下的消息:


host1# zfs send -i tank/dana@snap4 tank/dana@snap5 | ssh host2 zfs recv newtank/dana
cannot receive: destination has been modified since most recent snapshot

-F 选项成功之前,会执行以下检查:

发送和接收复杂的 ZFS 快照流

本节介绍如何使用 zfs send -I-R 选项来发送和接收更复杂的快照流。

发送和接收复杂的 ZFS 快照流时,请牢记以下要点:


示例 7–1 发送和接收复杂的 ZFS 快照流

可以使用 zfs send -I 选项将一组增量快照合并为一个快照。例如:


# zfs send -I pool/fs@snapA pool/fs@snapD > /snaps/fs@all-I

然后,您可以删除 snapBsnapCsnapD


# zfs destroy pool/fs@snapB
# zfs destroy pool/fs@snapC
# zfs destroy pool/fs@snapD

要接收组合快照,可以使用以下命令。


# zfs receive -d -F pool/fs < /snaps/fs@all-I
# zfs list
NAME                      USED  AVAIL  REFER  MOUNTPOINT
pool                      428K  16.5G    20K  /pool
pool/fs                    71K  16.5G    21K  /pool/fs
pool/fs@snapA              16K      -  18.5K  -
pool/fs@snapB              17K      -    20K  -
pool/fs@snapC              17K      -  20.5K  -
pool/fs@snapD                0      -    21K  -

您还可以使用 zfs send -I 命令来合并快照和克隆快照,以创建一个合并数据集。例如:


# zfs create pool/fs
# zfs snapshot pool/fs@snap1
# zfs clone pool/fs@snap1 pool/clone
# zfs snapshot pool/clone@snapA
# zfs send -I pool/fs@snap1 pool/clone@snapA > /snaps/fsclonesnap-I
# zfs destroy pool/clone@snapA
# zfs destroy pool/clone
# zfs receive -F pool/clone < /snaps/fsclonesnap-I

可以使用 zfs send -R 命令将 ZFS 文件系统和所有后代文件系统复制到一个已命名的快照中。接收此流时,所有属性、快照、后代文件系统和克隆都将被保留。

在以下示例中,将创建用户文件系统的快照。为所有用户快照创建一个复制流。然后,原始文件系统和快照将被销毁并恢复。


# zfs snapshot -r users@today
# zfs list
NAME                USED  AVAIL  REFER  MOUNTPOINT
users               187K  33.2G    22K  /users
users@today            0      -    22K  -
users/user1          18K  33.2G    18K  /users/user1
users/user1@today      0      -    18K  -
users/user2          18K  33.2G    18K  /users/user2
users/user2@today      0      -    18K  -
users/user3          18K  33.2G    18K  /users/user3
users/user3@today      0      -    18K  -
# zfs send -R users@today > /snaps/users-R
# zfs destroy -r users
# zfs receive -F -d users < /snaps/users-R
# zfs list
NAME                USED  AVAIL  REFER  MOUNTPOINT
users               196K  33.2G    22K  /users
users@today            0      -    22K  -
users/user1          18K  33.2G    18K  /users/user1
users/user1@today      0      -    18K  -
users/user2          18K  33.2G    18K  /users/user2
users/user2@today      0      -    18K  -
users/user3          18K  33.2G    18K  /users/user3
users/user3@today      0      -    18K  -

以下示例使用 zfs send -R 命令来复制 users 数据集及其后代,并将复制的流发送到另一个池 users2


# zfs create users2 mirror c0t1d0 c1t1d0
# zfs receive -F -d users2 < /snaps/users-R
# zfs list
NAME                 USED  AVAIL  REFER  MOUNTPOINT
users                224K  33.2G    22K  /users
users@today             0      -    22K  -
users/user1           33K  33.2G    18K  /users/user1
users/user1@today     15K      -    18K  -
users/user2           18K  33.2G    18K  /users/user2
users/user2@today       0      -    18K  -
users/user3           18K  33.2G    18K  /users/user3
users/user3@today       0      -    18K  -
users2               188K  16.5G    22K  /users2
users2@today            0      -    22K  -
users2/user1          18K  16.5G    18K  /users2/user1
users2/user1@today      0      -    18K  -
users2/user2          18K  16.5G    18K  /users2/user2
users2/user2@today      0      -    18K  -
users2/user3          18K  16.5G    18K  /users2/user3
users2/user3@today      0      -    18K  -

远程复制 ZFS 数据

可以使用 zfs sendzfs recv 命令,将快照流表示从一个系统远程复制到另一个系统。例如:


# zfs send tank/cindy@today | ssh newsys zfs recv sandbox/restfs@today

此命令发送 tank/cindy@today 快照数据,并在 sandbox/restfs 文件系统中予以接收。该命令还会在 newsys 系统上创建 restfs@today 快照。在此示例中,已将用户配置为在远程系统上使用 ssh