ZFS系列(十)快照和克隆

ZFS里面的快照和Linux LVM中的快照是类似的。快照是只读的,它是你做快照的时候的文件系统的一份镜像复本。可以想象成对外部世界的一个数字照片,即使外部世界发生了变化,然而那个照片还是保留了拍下照片的那个时候的外部世界的样子。

您可以在池中保留至多2^64个快照,ZFS快照是持久化的,即使重启也不会丢失,而且它们不需要任何额外的备份存储;它们与其他数据一样使用相同的存储池。如果您还记得我们关于“写时复制”文件系统特性的文章,您应该会记得我们关于Merkle树的讨论。ZFS快照是处于该状态的Merkle树的副本,但我们要确保该Merkle树的快照永远不会被修改。

创建快照几乎是瞬时的,而且成本低廉。但是,一旦数据开始更改,快照将开始存储数据。如果您有多个快照,那么将在所有快照中将记录多个增量。然而,根据您的需要,快照仍然可以非常便宜。

创建快照

你可以创建两种类型快照:池快照和数据集快照。您想要哪种类型的快照取决于您。但是,您必须为快照指定一个名。快照名的语法为:

  • pool/dataset@snapshot-name
  • pool@snapshot-name

创建快照需要使用“zfs snapshot”命令,比如,要对数据集“tank/test”创建快照,应该执行如下命令:

1
# zfs snapshot tank/test@tuesday

因为快照是一类只读的文件系统,所以无法像标准的ZFS数据集或者存储池那样可以进行属性修改,比如你想对一个快照启用压缩特性,将会发生如下情况:

1
2
# zfs set compression=lzjb tank/test@friday
cannot set property for 'tank/test@friday': this property can not be modified for snapshots

列出快照

快照可以通过两种方式显示:通过访问数据集根目录下的隐藏的”.zfs”目录,或者使用“zfs list”命令。首先,让我们讨论隐藏目录。

1
2
3
4
5
# ls -a /tank/test
./ ../ boot.tar text.tar text.tar.2
# cd /tank/test/.zfs/
# ls -a
./ ../ shares/ snapshot/

即使使用“ls -a”命令,“.zfs”目录也不可见,不过我们可以cd到这个目录中去。如果你想让“.zfs”目录可见,你可以更改该数据集上的“snapdir”属性。有效值是”hidden”和”visible”。默认情况下,它是隐藏的。让我们来试试:

1
2
3
# zfs set snapdir=visible tank/test
# ls -a /tank/test
./ ../ boot.tar text.tar text.tar.2 .zfs/

另一种显示快照的方法是使用”zfs list”命令,并传入”-t snapshot”参数,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# zfs list -t snapshot
NAME USED AVAIL REFER MOUNTPOINT
pool/cache@2012:12:18:51:2:19:00 0 - 525M -
pool/cache@2012:12:18:51:2:19:15 0 - 525M -
pool/home@2012:12:18:51:2:19:00 18.8M - 28.6G -
pool/home@2012:12:18:51:2:19:15 18.3M - 28.6G -
pool/log@2012:12:18:51:2:19:00 184K - 10.4M -
pool/log@2012:12:18:51:2:19:15 184K - 10.4M -
pool/swap@2012:12:18:51:2:19:00 0 - 76K -
pool/swap@2012:12:18:51:2:19:15 0 - 76K -
pool/vmsa@2012:12:18:51:2:19:00 0 - 1.12M -
pool/vmsa@2012:12:18:51:2:19:15 0 - 1.12M -
pool/vmsb@2012:12:18:51:2:19:00 0 - 1.31M -
pool/vmsb@2012:12:18:51:2:19:15 0 - 1.31M -
tank@2012:12:18:51:2:19:00 0 - 43.4K -
tank@2012:12:18:51:2:19:15 0 - 43.4K -
tank/test@2012:12:18:51:2:19:00 0 - 37.1M -
tank/test@2012:12:18:51:2:19:15 0 - 37.1M -

注意,默认情况下,该命令将显示所有池的所有快照。
如果希望输出更具体,可以查看给定父节点的所有快照,无论它是数据集还是存储池。您只需要传递“-r”参数以进行递归,然后提供父节点名称。在本例中,我将只看“tank”的快照,而忽略“pool”中的快照:

1
2
3
4
5
# zfs list -r -t snapshot tank
NAME USED AVAIL REFER MOUNTPOINT
tank@2012:12:18:51:2:19:00 0 - 43.4K -
tank@2012:12:18:51:2:19:15 0 - 43.4K -
tank/test@2012:12:18:51:2:19:00 0 - 37.1M -

消耗快照

与销毁存储池或ZFS数据集一样,也可以使用类似的方法销毁快照。要销毁快照,使用“zfs destroy”命令,并提供要销毁的快照作为参数:

1
# zfs destroy tank/test@2012:12:18:51:2:19:15

需要知道的一件重要的事情是,如果快照存在,它就被认为是数据集的子文件系统。因此,在销毁所有快照和嵌套数据集之前,不能删除数据集。

1
2
3
4
5
# zfs destroy tank/test
cannot destroy 'tank/test': filesystem has children
use '-r' to destroy the following datasets:
tank/test@2012:12:18:51:2:19:15
tank/test@2012:12:18:51:2:19:00

重命名快照

可以重命名快照,但是必须在创建快照的存储池和ZFS数据集中重命名快照。重命名快照非常简单:

1
# zfs rename tank/test@2012:12:18:51:2:19:15 tank/test@tuesday-19:15

回滚快照

如果不讨论将文件系统回滚到上一个快照,那么关于快照的讨论就不完整。

回滚到上一个快照将丢弃该快照与当前时间之间的任何数据更改。默认情况下,只能回滚到最近的快照。为了回滚到更早的快照,您必须销毁当前时间和希望回滚到的快照之间的所有快照。如果这还不够,则必须在开始回滚之前卸载文件系统。这意味着停机时间。

要回滚“tank/test”数据集到“tuesday”快照,我们会发出以下命令:

1
2
3
4
5
# zfs rollback tank/test@tuesday
cannot rollback to 'tank/test@tuesday': more recent snapshots exist
use '-r' to force deletion of the following snapshots:
tank/test@wednesday
tank/test@thursday

与上面提到的一样,我们必须删除“@wednesday”和“@thursday”快照,然后才能回滚到“@tuesday”快照。

ZFS克隆

ZFS克隆是一个从快照“升级”的可写文件系统。克隆只能从快照创建,只要克隆存在,对快照的依赖就会保持。这意味着,如果你克隆了快照,就不能直接销毁这个快照。克隆依赖快照提供给它的数据,所以在销毁快照之前,必须先销毁克隆。

创建克隆几乎是瞬时的,就像快照一样,最初并不会占用任何额外的空间。相反,它会占用快照的所有初始空间。当数据在克隆中被修改时,它开始占用与快照分离的空间。

创建ZFS克隆

使用“zfs clone”命令、要克隆的快照和新文件系统的名称来创建克隆。克隆不需要驻留在与克隆相同的数据集中,但它需要驻留在相同的存储池中。 例如,如果我想克隆“tank/test@tuesday”快照,并给它命名为“tank/tuesday”,我将运行以下命令:

1
2
3
4
5
6
7
# zfs clone tank/test@tuesday tank/tuesday
# dd if=/dev/zero of=/tank/tuesday/random.img bs=1M count=100
# zfs list -r tank
NAME USED AVAIL REFER MOUNTPOINT
tank 161M 2.78G 44.9K /tank
tank/test 37.1M 2.78G 37.1M /tank/test
tank/tuesday 124M 2.78G 161M /tank/tuesday

销毁克隆

与销毁数据集或快照一样,我们使用“zfs destroy”命令。再强调一遍,在您销毁克隆之前,不能销毁快照。所以,如果我们想要摧毁“tank/tuesday”的克隆,用如下命令,就像销毁其他数据集一样:

1
# zfs destroy tank/tuesday

结语

因为保存快照非常便宜,所以建议经常对数据集进行快照。Sun Microsystems提供了一个Time Slider ,它是GNOME Nautilus文件管理器的一部分。Time Slider 保存快照的方式如下:

  • 频率–每15分钟做一次快照,保留4张快照
  • 每小时–每小时快照,保留24张快照
  • Daily –每天快照,保留31个快照
  • 每周–每周快照,保留7个快照
  • Monthly–每月快照,保留12个快照
    不幸的是,Time Slider 不是标准GNOME桌面的一部分,所以GNU/Linux上没有。 然而,Linux上的ZFS开发人员已经创建了一个“zfs-auto-snapshot”包,如果运行Ubuntu,你可以从项目的PPA中安装它。如果你运行的是另一种GNU/Linux操作系统,您可以轻松地编写一个Bash或Python脚本来模拟该功能,并将其放在您的根用户的crontab中。

因为快照和克隆都很便宜,所以建议您充分利用它们。克隆对于测试部署虚拟机或从生产环境克隆的开发环境非常有用。而且可以很容易地销毁它们,而不会影响创建快照的父数据集。

参考资料

https://pthree.org/2012/12/19/zfs-administration-part-xii-snapshots-and-clones/

如果你觉得本文对你有帮助,欢迎打赏