第四章:复制

究竟什么是 [/ˌrepləˈkāSH(ə)n/] (replication)?在ZFS中,它意味着在其他地方制作文件系统的精确副本。另一个位置可以是

您可以声明“我想要这个文件系统在那个地方”,并实现它。ZFS复制具有一些设计功能,使其特别强大。

dump(8)rsync(1) 这样的程序期望接收方以某种方式确认接收到数据。ZFS复制过程是单向的,发送方不需要来自接收方的任何反馈。由于复制不需要任何确认,ZFS接收方不需要任何情报;它只需要接受字节流并对其进行处理。

复制系统与快照集成。快照是一个静态的、不变的实体,这意味着传输的ZFS数据集是完全一致的,这与转储或同步(dumping or rsyncing)活动文件系统不同。基于快照的复制还意味着您可以执行增量复制,只发送在两个快照之间更改的块。使用增量复制,您不必将同一数据发送两次。

ZFS的复制功能旨在充分利用所有磁盘。在机器之间复制数据的速度的唯一限制是网络链路的速度。

ZFS复制由两部分组成:

第四章:复制但是我有Rsync!为什么复制?基本复制本地复制查看复制远程复制复制用户和数据集数据集完整远程复制增量复制增量复制假设差异复制SSH 带宽限制增量复制的复杂性递归复制高级发送选项发送属性去重数据流调试和测试大的和小的块高级接收选项路径和挂载管理回滚变化调试和测试接收时克隆书签可恢复发送自动复制使用zxferZxfer 拉取模式旋转快照保留旧快照属性和灾难恢复更多 Zxfer 选项

但是我有Rsync!

几十年来,rsync(1) 一直是机器之间同步文件的标准工具。为了同步文件,rsync 遍历目录树,计算每个文件的时间戳(timestamp)和加密校验和(cryptographic checksums),并将其与远程端的文件进行比较。许多组织已经部署了广泛的基于 rsync 的基础设施。

ZFS从磁盘开始设计,以实现最佳性能。它严重击败了 rsync ,因此 rsync 的妈妈需要紧急医疗护理。ZFS维护磁盘上每个快照之间不同的块列表。复制过程不需要确定哪些文件已经更改——文件系统本身已经有了这些信息。复制过程立即开始以尽可能快的速度发送这些块。由于更改的块包含重新组装文件的所有元数据,复制过程甚至不需要知道这些块属于哪些文件。

rsync 遍历文件系统、查看每个文件、检查其时间戳、计算校验和并将这些与另一端的版本进行比较时,ZFS已经完成。如果有10TB数据,但只有1GB发生了变化,rsync 需要检查每一个文件(时间戳、计算校验和,并将其与另一端的版本进行比较),而ZFS则只抓取1GB的更改块并发送它们。

需要更快的 rsync 同步的系统管理员可以告诉 rsync 进行欺骗,并假设本地和远程文件的上次修改时间相同,则文件没有更改。(这实际上并不总是正确的,但不要认为系统管理员能更好地了解 rsync )。当文件的时间戳发生更改时, rsync 计算文件两侧块的校验和,并比较校验和。如果发现差异,则计算增量并将其发送出去。这意味着,如果您对大文件进行了小的更改, rsync 必须在本地和远程读取整个文件并进行校验和。使用 rsync 在备份机器上维护500GB VM磁盘映像的副本会消耗大量的磁盘带宽和处理器时间。

ZFS中的每个块都有一个 birthtime ,即创建块时的事务组ID。复制进程发送比上次运行复制时更新的任何块。这些块是来自新文件,还是来自大文件的中间并不重要。

当您定期同步文件系统时,基于快照的复制的优势真正发挥了作用。假设您在远程备份服务器上复制快照。一小时后,您将创建一个新快照,并以增量方式将该快照发送到备份服务器。ZFS在几秒钟内完成,而 rsync 仍在遍历第一级目录。

rsync(1) 支持快照备份模式。然而,rsync 中的快照与ZFS快照完全不同。使用 rsync 快照,如果修改1 GB文件的1个字节,rsync将保留该文件的两个完整副本。另一方面,ZFS保留单个块的两个不同副本。该文件的两个版本共享其余的块。

rsync 的防御中,它是一种跨平台、跨文件系统的工具。可以使用 rsync 在操作系统之间和文件系统之间同步目录树。Lucas使用 rsync 在完全不同的类Unix平台(如FreeBSD、AIX和Linux)之间同步目录树。

但如果您使用的是ZFS,则复制特别适合处理ZFS。复制理解并复制ZFS属性。它可以维护克隆与其父级之间的关系,而 rsync 将丢失此链接并放弃所有节省的空间。rsync(1) 在原始块设备上不能很好地工作,但ZFS复制可以与zvols一起工作。复制也使用文件系统的集成校验和,因此不会有您收到的文件与原始文件存在某种差异的风险。

ZFS复制也是版本无关的。只有在故意添加命令行标志以请求新池功能时,才会启用这些功能。这使得ZFS复制可以轻松地在不同版本的池之间移动数据。

为什么复制?

复制以多种方式发挥作用:最明显的是在备份中,但也常用在测试、虚拟化和数据迁移中。

您确实记得RAID不是备份,对吗?即使RAID-Z3也不是适当的备份。当您的机器着火时,当执法部门没收托管提供商的所有硬件时,或者当您意外删除该重要数据集时,RAID-Z3将不会拯救您。将重要池复制到外部驱动器、备份计算机或磁带库。现在,即使硬件完全丢失,也可以将其取回。ZFS的美妙之处在于,在初始复制之后,每个备份都可以是增量的。

让我们更进一步。也许仅仅能够恢复您的数据是不够的。您必须保证您的数据始终可以全天候(24x7x365)访问。您需要高可用性。使用每隔几分钟的增量快照将数据复制到第二个和第三个服务器。现在,您的数据总是可以在n+2热备盘服务器上运行。将其中一个备份服务器放在远程位置,即使您的设备完全损坏,也会受到保护。

所以,这里有一个很好的客户数据集。您希望用它来测试新版本的计费系统。您需要在开发环境中使用完全独立的副本,而不是在同一台机器上克隆数据。无论目标是远程机器还是同一池上的新数据集,ZFS复制都是复制数据的最快、最可靠的方法。

您是否有几十个或数百个相同的机器、VM或容器?使用ZFS复制在任何地方部署精心制作的映像。如果正确设计系统,甚至可以使用增量复制来部署更新。

复制还大大简化了数据迁移,即使是远距离的海量数据。也许你必须将一个巨大的数据集迁移到国家的另一边,或者迁移到整个地球。有了足够的数据,即使是同一数据中心中的10 Gb/s以太网也显得太慢了!假设您有许多TB的数据,这些数据总是在使用中,并且经常发生微小的变化,例如客户数据库。通过互联网将数据复制到国家或世界的另一端需要几天时间,但到那时,数据将发生变化。基于 rsync 的复制过程耗时太长,可能永远赶不上。您的数据库管理员是聪明的人,可能会想出一个聪明的计划来移动具有某种复杂数据分段的数据。这些计划可以成功完成,但增加了风险,并且总是带来沉重的工作量和挫折感。

如果可用于同步的带宽超过数据中的更改速率,请改用ZFS。您的第一次ZFS复制(包括来自这个巨大数据集中的每个数据片段)可能需要几天或几周的时间。您甚至可能会发现,通过磁带和隔夜发货来执行第一次同步更为实际。然而,当此同步完成时,从新快照进行第二次复制所需的时间不会太长。通过几次迭代,只要您的更改速率慢于可用于备份的带宽,ZFS复制就可以赶上几乎实时的速度。

在Big Switch Day,在复制最近的一组更改时,冻结数据集几分钟。您可能会对负载平衡器、防火墙、新服务器和支持如此大规模数据集所需的所有其他小工具感到恐慌,但数据本身并不是问题。

基本复制

ZFS不复制数据集。它复制快照。快照在复制期间(或任何其他时间)不会更改,因此可以保证它们在内部一致。首先创建数据的快照:

现在让我们把快照复制到本地和远程主机。

本地复制

ZFS复制是单向的,这意味着它不需要来自接收器的任何反馈。这意味着您可以使用标准Unix shell重定向和管道将快照转储到任何其他程序中。在这里,我将 zfs send 的输出输入到一个常规文件中。(如果添加 -v 标志,zfs send 将每秒打印一次进度摘要。)

这个文件是我们首次使用ZFS复制,因此它不是增量的。它包含快照中的所有内容。它的大小于数据集大致相同。然而,它并不像现在这样有用——很少有人能在不将其转换回文件系统的情况下读取流式文件系统。因此,我们使用 zfs receive 将此数据集反馈给ZFS:

zfs(8)backup_file 读取复制流,并从中创建一个新的数据集,这是原始数据集的精确副本。

您不需要在本地复制过程中使用文件。这是一个类似Unix的系统。我们有管道的奇迹。该主机在根池上有主目录,但我正在将副本移动到新池。

现在我们可以整理几个数据集挂载点,并将主目录移动到新池中。

ZFS的单向特性可以复制到任何可以瞄准命令的对象,比如磁带。使用管道,可以通过SSH将 zfs send 放入 zfs receive ,从而在远程计算机上复制数据集。

查看复制

想要查看流文件的内部吗?zstreamdump(8) 实用程序检查流并公开其详细信息。您可以检查文件,或直接从 zfs send 读取。

zstreamdump 程序为 zfs send 流中的每个快照响应一个这样的部分:

此输出包含大量关于 zfs send 流的信息。最难的是,没有一个是以一种对人类友好的方式呈现的。即使如此,我们也可以从中提取一些信息块。

creation_time 段给出 zfs send 运行的时间,以Unix纪元的秒为单位,当然是16进制。使用以下命令(date -r 0x ——0x表示后面的值是16进制的)可将其转换为人类可读的数值:

在非FreeBSD主机上,data 命令可能不接受16进制值。可以尝试以下方法:

每个快照都有一个人类可读的名称,以 toname 的形式给出。此例中快照称为 mypool/somedata@snappycomeback ,并阐明了数据集和快照使用有意义的名称的重要性。

流中的每个快照也具有全局唯一标识符或GUID。此快照的GUID显示在 toguid 字段中。

fromgid 字段用于增量ZFS发送(请参阅本章后面的“增量复制”),仅包括两个快照之间的更改。在这个例子中它为零,这意味着这个 zfs send 流包含一个完整的快照。它不是增量的。由于它是一个完整的快照,因此将该 zfs send 流恢复到活动数据集是有意义的。(您可以恢复增量ZFS流,但需要它所基于的快照的副本。)

如果流中有多个快照(例如,从增量或递归 zfs send ),则可以使用 toguidfromguid 值来拼凑快照的组合方式。然而,将 zfs send 流恢复到数据集并以这种方式查看它可能更容易。

每个部分以 checksum 结束。在本节中,不能使用校验和手动验证快照,但知道ZFS使用校验和是很好的。

在每个快照的详细信息之后,zstreamdump 打印摘要:

摘要包括一大堆ZFS内部元数据。这里最有趣的部分是 DRR_BEGIN 记录的数量,它对应于该流中的快照数量。末尾的大小以字节为单位。写入大小是流中包含的数据的大小,而流长度是流本身的大小。(ZFS send 流具有用于将数据恢复到磁盘的元数据,而不需要写入磁盘。)

远程复制

为了将ZFS复制到远程主机,远程主机需要可以接受复制的用户和到该远程主机的安全管道。最常见的安全复制管道类型是SSH,因此我们假设这是您的工具。从长远来看,使用SSH的最简单方法是使用基于密钥的身份验证。如果您不熟悉基于密钥的身份验证,请参阅任何数量的在线教程或Lucas的《SSH Mastery》(Titted Windmill Press,2012)。

您可以使用 root 帐户接收复制流,但这意味着允许SSH以 root 身份登录。SSH作为 root 是个坏主意。不要这样做。你真的想让这个随机的家伙在互联网上维护一些shell脚本吗?相反,创建一个无特权用户并为其分配复制权限,如第2章中所述。

类似地,虽然可以以 root 身份发送ZFS数据集,但您可能希望操作员或普通用户能够发送数据集。

复制用户和数据集

在发送主机和接收主机上,我们创建一个专用于复制的用户。我们的示例用户称为 replicator。它需要shell,但不需要特殊的组成员身份。

在发送主机上,用户 replicator 需要对发送的数据集具有发送和快照权限。此处,我们给 replicator 用户主目录上的这些权限:

发送用户需要SSH密钥对。在发送端和接收端都使用自己账户的用户可以使用自己的SSH密钥,对于专用账户,使用 ssh-keygen(1) 生成密钥:

ssh-keygen 程序希望你提供密码短语。如果使用此账户发送ZFS数据集,应使用密码短语;如果这是个自动化脚本,建议使用空密码短语。

密钥文件为 .ssh/id_rsa.pub 【新版系统默认生成的是 id_ed25519 密钥对】,保存在用户的主目录中。我们还建议限制哪些主机可以使用此密钥登录到远程计算机,以帮助在密钥被盗时保护远程主机和您的备份。

现在让这个无特权用户在远程计算机的账户中安装公钥。此处我们将新密钥发送到主机 hotspare 上具有相同用户名称的账户:

验证你是否可以用此用户身份登录到接收主机。

在接收机上,用户必须拥有接收方数据集的挂载点。系统还必须允许无特权用户使用 vsf.unsermount sysctl将此文件系统挂载到它们自己的目录上。

我们的无特权用户需要对目标数据集有一系列ZFS权限:compressioncreatemountmountpointreceive。此处,我们为用户 replicatorremotepool/backup 数据集上分配权限。如果你打算自动化ZFS复制,包括销毁过期的快照,则需要添加 destroy 权限。

此无特权用户现在可以复制此数据集。

如果要复制数据集的所有属性,则必须允许 replicator 用户设置所有这些属性。有关如何创建权限集的详细信息,请参阅第2章。

数据集完整远程复制

要复制ZFS数据集,首先创建快照。我们授予了那个无特权用户权限,可以专门为此目的创建快照,开始吧:

现在使用 zfs send 命令传输快照,使用SSH管道,转储到 zfs receive 。记住,ssh(1) 允许在远程主机上运行命令。由于这是我们第一次复制此数据集,因此发送流包括快照中的每个块。

除了复制到另一台计算机上的池之外,您还可以复制到同一个池或同一台机器上的第二个池、文件或管道。复制到文件或管道对于备份非常有用,例如复制到磁带或其他文件系统。

如果愿意,可以让一个主机登录到另一个主机来触发 zfs send ,将ZFS复制从推模式更改为拉模式。

本书假设您从本地数据集发送数据以实现一致性,但一切都是朝着相反的方向进行的。

增量复制

真正的力量来自增量复制。现在我们已经复制了截至周一的数据集中的所有数据,周二的复制只需要发送已更改的块。命令的 receive 端根本不会改变,但在 send 端,我们使用 -i 选项来指示最近发送的快照:

ZFS只发送 @monday@tuesday 快照之间发生变化的块,节省了时间和带宽。

现在看看接收端上的数据集:

显示了两个快照。

增量备份的一个常见错误是没有指定远程系统上存在的最后一个快照。如果不指定传输的最新快照,则会出现错误。

这样的错误消息的危险在于,它提供了错误的方法,而不是建议解决潜在问题的方法。-F 选项强制覆盖远程数据集会清除旧快照并重新发送所有数据。

使用 -i 时,可以跳过快照名称前面的@符号,-i 选项意味着“这是一个快照”,因此它可以安全地假设你想把@放在前面,但就是不想被打搅。

增量复制假设

到磁带的增量备份几乎是固定的:您可能会覆盖它们,但在21世纪,您不会直接在磁带上编辑文件。不过,写入磁盘的增量备份非常容易更改。

增量复制要求接收方的数据集副本在复制运行之间不发生变化。副本中的更改会破坏整个过程。如果编辑数据集的备份副本,则下一次增量更新将不再插入备份副本。如果要在备份计算机上编辑数据集副本,请创建接收的数据集的克隆并进行编辑。

如果有人意外或无意地编辑了复制副本,请将更改回滚到最后一个通用快照。通过将 -F 标志添加到 zfs receive 命令,让接收器强制回滚到匹配的远程快照。

通过将复制数据集的ZFS readonly 属性设置为 on ,防止对复制数据集进行更改。使用前面给出的权限,用户可以添加快照以只写入数据集:

仍然可以在 remotepool/backup 下添加快照。可以检测数据集中的文件。但是,如果不更改ZFS readonly 属性,任何人都无法编辑文件。任何拥有这种访问权限的人都应该更好地了解,或者迫切需要立即使该数据集上线。

差异复制

ZFS复制可以在同一数据集上的任意两个快照上完成,因此您也可以进行差异备份。使用 -I 标志(大写 I)而不是 -i 发送存在于两个快照之间的所有快照。

假设周二的快照复制因随机网络问题失败。在周三,我们希望同时发送周二和周三的快照:

接收人现在拥有周二的快照,尽管从未明确发送过。

有运行备份经验的人会意识到,增量(incremental)和差异(differential)这个两个词的方式与大多数备份软件略有不同。备份软件旨在将块发送到磁带,并最大限度减少恢复文件所需的磁带数量。我们可以发明一种新的语言,我们可以去挖掘完全合适但不熟悉的单词,或者我们可以稍微扩展现有的语言。

SSH 带宽限制

您可能会发现SSH连接的速度不够快,无法满足您的需要。您中那些需要每秒超过几百兆字节的复制速度的人可能应该考虑外部安全解决方案,如专用VPN。SSH在没有非常具体的修改的情况下不会那么快地传输数据,因此考虑 mbuffer(1)

增量复制的复杂性

ZFS复制是单向的,从发送方到接收方。发送方不会从接收方得到任何反馈,允许将流转储到几乎任何东西。在决定增量(incremental)复制和差异(differential)复制时,这一点变得很重要。

假设每天自动对数据集进行快照,并希望将其发送到远程服务器。将 @monday 快照复制到远程池:

检查远程主机以验证 @monday 快照的存在:

现在增量复制 @tuesday 快照:

检查远程主机,可以找到两个快照:

星期三你出去闲逛了,我是说,“生病了”——所以你没有做复制。星期四,您希望赶上进度,因此需要对 @thursday 快照进行差异复制。

我们的热备盘主机有四个快照:

但假设考拉相关的混乱让你周四晚上睡不着觉。你在星期五早上蹒跚而行,决心在不破坏任何东西的情况下度过这一天。设置当天的复制时,您意外地尝试从 @monday@friday 执行增量(-izfs send

你可能很清楚你没有修改这些快照。没有人能登录到那台机器。但它已经被修改了,@tuesday、@wednesday、@thursday快照挡住去去路。

如果你不确定远程端可能存在哪些快照,可以使用 -I 发送所有中间快照。或者,可以在 zfs send 命令中使用 -F 选项,以强制它删除任何阻碍。

使用 zfs receive -F “删除任何阻碍“的不愉快的副作用是它会破坏中间快照。

我们想要回哪些快照。所以我们再试一次。在热备盘主机上,删除最新的快照:

现在,让发送方重新传输所有这些快照,一次一个或全部。此处,我们发送了一个快照,以确保没有破坏任何东西:

复制是单向的这个事实意味着,在差异备份中,可以发送重叠,传输远程端已经存在的快照。如果我们在 @monday@friday 之间发送所有快照,而 @tuesday 快照已经存在与远程池中,则源会发送所有更改的数据,甚至是远程端已经拥有的块。远程端快速转发它拥有的块,然后创建它没有的快照——此处是 @wednesday@friday

这里的最佳做法是避免考拉。和他们的混乱(mayhem)。

递归复制

ZFS也支持递归复制(recursive replication),即在一个命令中复制数据集及其所有子数据集。这是一个包含三个数据集的本地池:

对数据集及其子数据集进行递归快照:

现在,使用递归发送(zfs send -R)同时复制该快照及其所有子级。

递归发送也以完全相同的方式与增量(-i)和差异(-i)备份一起工作。现在,您可以同时强制销毁数据集及其子级!

高级发送选项

发送方可以通过多种方式更改其发送数据集的方式。

发送属性

要发送数据集属性和实际数据,请添加 -p 标志。当接收的数据集的属性与数据集上已经存在的属性不同时, zfs receive 尝试更改属性以匹配发送的属性。也就是说,如果您正在将属性从使用lz4压缩的数据集复制到已经使用 lz4zfs receive 不会对该属性进行任何操作。然而,如果发送方使用 gzip-9 压缩,则接收方将更改以匹配原始数据。

接收数据集的用户必须具有设置要复制的属性的权限。如果用户有权复制部分但不是全部属性,则会设置允许的属性,并拒绝不允许的属性。

假设源数据集的 dedup 设置为 oncompression 设置为 gzip-9 。接收数据集的 dedup 设置为 offcompression 设置为 lz4 。我们希望接收数据集使用相同的 compression ,但不是 dedup 设置。我们允许复制用户更改 compression

当我们发送数据集时,受到错误提示:

还好,我们不希望在副本上设置 dedup 属性。不过, compression 属性会根据需要进行复制。

为什么要复制属性,而不仅仅是将其设置在目标上?手动配置可能适用于压缩和 dedup 等简单属性,但不太适合 sharenfs 或者任何配额等复杂属性。

去重数据流

数据是否已经进行去重?它是否适合去重?ZFS允许你对 zfs send 的数据流进行去重。使用 -D 选项,每个唯一块仅发送一次。它不会改变接收者写入磁盘的内容,只会影响数据流。

去重数据流使用的去重内存集与磁盘去重使用的内存集不同。如果数据可以有效地进行去重,但去重使用了数GB的内存,则发送和接收主机都需要类似数量的内存来对数据流进行去重。zfs send 中不要轻易使用去重。

调试和测试

zfs send 支持几个选项,可以帮助调试、测试和监控。

大的和小的块

较新版本的ZFS可以支持大于128KB的磁盘块,并具有 large_blocks zpool(8) 功能。 -L 标记允许 zfs send 包含大块的数据,而不是将其分解为小块。接收者也必须支持大块。

对于块非常小的主机, -e 通过使用 embedded_data 特性缩小了数据流的大小。目标池必须支持 embedded_data 功能标志。

高级接收选项

接收方可以通过 zfs receive 的参数调整其存储转入ZFS流的方式。

路径和挂载管理

接收到的ZFS流包括源的池和数据集路径,可以保留或剔除此路径。

回滚变化

如果有人更改了接收到的数据集,则尝试向该副本增量添加新快照将失败。接收到的快照的数据集必须是原始的,zfs receive 才能进行增量或差异更新。

-F 选项告诉 zfs receive 回滚任何阻止接收此快照的更改。

调试和测试

zfs send 非常相似,zfs receive 支持冗长和无效果选项。

虽然冗长(verbosity)可能有用,但 -n 选项在接收数据方面的实用性有限。主机将通过网络向该主机发送数据,接收方将进行一些数值分析并丢弃数据。要将数据写入磁盘,必须重新发送。

接收时克隆

你可能需要发送一个你知道你会想处理的数据集。从FreeBSD 10.3开始,您可以告诉 zfs receive 将传入的增量复制流存储为克隆而不是快照。接收时克隆仅适用于增量复制

要让 zfs receive 并创建克隆,请添加 -o 标志,并将源定义为要克隆的数据集。zfs receive 命令获取该数据集,将传入的快照添加到其中,并将克隆从原始数据集中分叉出来。

在本章中,我们一直在将 zroot/usr/home 备份到远程服务器。假设我们想要一个周三快照的读写克隆。我们将从克隆周二快照开始。

-o origin 语句告诉 zfs receive ,我们从快照 remotepool/usr/home@tuesday 开始创建克隆。最后一个参数给出了克隆的名称,remotepool/usr/wedshome 。现在,我们可以进入 remotepool/usr/wedshome 并进行任何我们想要的更改,而不会干扰进一步的复制。

但是,请记住,创建此克隆不会将传输的快照添加到原始目标中的快照中。如果我们还想创建remotepool/usr/home@wednesday ,我们必须在不使用 -o origin 选项的情况下重新传输它。

书签

快照可能会占用大量空间,特别是在繁忙的文件系统上。如果您有用户构建新的软件,下载ISO,然后丢弃它们,并到处转储核心文件,则快照可能会变得相当大。不幸的是,增量复制是在快照的基础上构建的。书签是一种绕过保留最旧快照的需要的方法,同时仍然执行增量复制。

增量复制不需要知道所有已发送的块。它必须知道已经发送的最小区块的出生时间,以便它可以发送所有较年轻的区块。书签是精简(stripped-down)快照,仅保留快照中最新块的出生时间。您可以使用书签作为增量复制的起点。

创建工作日数据集的 @friday 快照的书签。书签名称以哈希标记(#)开头。

使用 zfs list 查看书签:

现在从源池中删除所有快照:

现在就只剩下书签:

周六,制作一个新的快照:

毫无帮助的是,书签列在快照之后,即使它们比快照旧。然而,ZFS命令行非常有表现力。为了使事情更容易,可以使用 -t 选项来告诉它只列出快照和书签。-s 属性告诉 zfs(8) 如何对输出进行排序,因此我们将数据 creation 属性进行排序,添加最大递归深度 -d 1 以忽略子数据集的快照:

现在使用 bm-friday 书签作为fromsnap,将 @shaurday 快照复制到远程主机:

远程主机将 @shaurday 快照捕获为增量快照,即使源主机不再有Friday的快照。

书签允许我们从源池中删除快照,节省空间,但将它们保留在目标池中,这样我们仍然可以引用旧版本的文件。

可恢复发送

仅仅因为ZFS使数据集复制变得简单,并不意味着现实世界可以合作。随着数据集的大小增加,一些瞬态网络问题将中断连接并中断流的可能性增加。如果您几乎完成了互联网上40GB的数据流,那么ISP的两分钟停机可能会引发一些理所当然的愤怒。不要用斧头追赶航母;改用可恢复的 zfs send ,让您恢复中断的复制。可恢复 zfs send 首次出现在2016年初的FreeBSD 10.3中。

使用zfs receive -s 选项启用ZFS发送流可恢复。

mypool/from 数据集的大小为几GB。然而,通过将 -s 添加到 zfs receive 语句,我们使流可恢复。这很好,因为我们将用 CTRL-C 中断传输。

当然,由于ZFS复制是单向的,因此发送方不知道哪个块会阻止接收方实际捕获并写入磁盘。如果没有可恢复的发送,则必须重新启动整个传输。

在接收主机上,部分接收的数据集具有新属性 receive_resume_token 。发送方需要此属性的值来拾取它停止的位置。

现在,使用 -t 选项将该令牌提供给发送方。不需要包含源数据集,因为令牌包含zfs发送所需的一切。不过,添加-v显示更多关于传输的细节:

zfs receive 完成后,这个属性 receive_resume_token 会变为空。

如果你不继续发送,目标池上会有一个不可用的、不完整的数据集,占用了更好地被任何东西使用的空间。用 -A 删除。

这将删除部分接收到的流并释放该空间。

自动复制

每个人都需要备份,但必须手动运行的备份不是备份,因为它们不会发生。当然,你会做一次或两次,但有一天咖啡壶会打破,你将几乎无法记住你离开了你的愤怒(spleen)。可靠的备份需要自动化和测试。测试总是您的问题,但对于自动化,我们有 zxfer

zxfer(8) 检查选择的本地和远程数据集,确定必须复制哪些快照来同步这两组数据,并发送数据集。一旦快照从本地池中删除,它还可以删除远程端的快照。

FreeBSD默认不包括 zxfer ,但您可以轻松地用 pkg 安装它。由于 zxfer 可以在push和pull模式下工作,因此您只需要将其安装在其中一个系统上。对于我们的演示,我们将在两个节点上安装它。

zxfer 命令当前不支持书签或可恢复复制。它也不会设置复制用户帐户。您必须像正常复制一样配置这些帐户、创建SSH密钥和设置权限。

使用zxfer

我们所有的复制示例都使用了推送模式;具有当前数据集的主机将它们推送到复制目标。我们将以类似的方式使用 zxfer 。使用 -T 启用推送模式,并登录远程主机。

使用 zxfer 需要声明是要复制单个数据集,还是复制数据集及其所有子数据集。 -R 标志启用递归,而 -N 表示单个数据集及其快照。对于备份,递归模式几乎总是正确的。

您还可以添加 -v ,用于详细模式。

如果双方的用户帐户相同,则可以跳过识别用户。

要记住的一件事是,有自己参数(argument)的参数不能与不需要参数的参数结合在一起。您可以使用 -v -T user@host ,但是 -vT user@hostzxfer 怨声载道。(由于 zxfer 是一个shell脚本,它使用 getopt(1) 来处理命令行参数,而不是更复杂语言中的花哨选项处理。)

在这里,我们将 zroot/somedata 数据集复制到主机远程上的池 remotepool/backups

如果为详细模式添加 -v ,您将看到 zxfer 传输每个快照。

一旦 zxfer 退出,主机远程就会拥有所有快照。

在这些快照之上的进一步复制可以在推送模式或拉取模式下运行。接下来让我们尝试拉取模式。

Zxfer 拉取模式

在拉取(pull)模式下,zxfer 通过SSH登录到远程计算机,并运行 zfs send 将快照传输回运行 zxfer 的主机。在登录名和主机上使用 -O 标志表示拉取模式。其他一切都是一样的。

现在在源主机上创建一个额外的快照。

在目标计算机上,运行 zxfer 以获取快照。在这里,我们添加了 -v 来显示实际情况的更多细节:

挂载的数据集将使用新快照进行更新。

旋转快照

如果您继续发送快照,最终您的远程池将填满。您可能希望销毁源计算机上不再存在的远程快照。使用 -d 来完成此操作。首先删除旧快照。

使用 -d 标志从目标中修剪(prune)所有已删除的快照:

在详细(详细)模式下,zxfer 显示它销毁的每个数据集以及它创建的数据集。

你可以看到你匆忙输入的错误命令会破坏你心爱的数据。

保留旧快照

一个常见的快照方案要求每15分钟制作一次快照,然后每小时、每天、每周和每月制作一次。(我们在 《FreeBSD Mastery:ZFS》中讨论了这样的轮换方案。)主机在几个小时后丢弃15分钟的快照,在几天后丢弃每小时的快照,以此类推。您当然希望在远程主机上丢弃这些15分钟的快照,但您可能希望远程主机在源销毁它们后保留一些快照。我们中的许多人希望将每周或每月的快照作为长期备份。

-g 标志允许您使用天数参数保护最旧的备份。例如,-g 375 告诉 zxfer 不要删除375天或更早的快照。

假设您想保留所有月度快照,但会自动删除从源中删除的任何其他快照。源在三个月后删除每月快照,但在六周后删除每周快照。六周等于42天。为系统异常增加一周,即49天。使用 -g 50 将告诉 zxfer 不要删除任何50天或更早的快照。

最终,您的备份池将填满。你必须进去清理那些太旧而不再有用的快照。这和清理公司的磁带柜没什么不同。

属性和灾难恢复

您通常希望复制复杂的属性,如 sharenfs 和任何配额。 -P 参数告诉 zxfer 将目标中的属性设置为与源匹配。

在某些情况下,您想知道属性是什么,但不想在复制后立即还原它们。zxfer 命令可以将数据集属性复制到文本文件中,以便稍后从该文件进行还原。

-k 标志告诉 zxfer 在复制副本的根目录中创建属性文本文件。该文件名为 .zxfer_backup_info ,后跟句点和池名。如果要将整个主机web5的 zroot 池复制到备份主机上的 remotepool/web5 ,则属性备份文件将位于 remotepool/wbe5/.zxfer_backup_info.zroot 中。

使用 -e 标志从该文本文件还原数据集和池属性。

一种常见的配置是,主机留出一个池来接受备份,然后留出一个池来进行灾难恢复。如果源计算机死机,您可以在本地使用 zxfer 将最新备份复制到灾难恢复池。您可以在 zxfer(8) 手册页中找到确切的示例,但这里有一个常见的示例,包括恢复属性。我正在将主机web5的备份还原到一个也称为 web5 的池中。

从新的 web5 池启动,您已恢复服务!

更多 Zxfer 选项

zxfer 程序有很多选项可以在恼人的情况下进行复制。

如果你有一个复杂的SSH设置,你可能需要在 zxfer 用户的 $HOME/.ssh/config 中设置一些客户端选项。或者,您可以将这些选项添加到 -O-T 的单引号中。

-O-T 标志也可用于注入SSH选项以及命令行参数。用户和主机之前的附加参数被馈送到SSH,而用户和主机之后的任何命令都以 zfs(8) 命令为前缀。(不过,配置ZFS数据集权限比使用 sudo 更好。)

-F 标志告诉 zfs receive 回滚任何阻止复制的数据集。如果你更改了复制的数据集, -F 会清除这些更改。

您可以让 zxfer 在运行前自动拍摄快照。它不会删除旧快照,因此它不是一个合适的快照轮换方案。然而,它适用于即时备份,将清理问题留到另一天。添加 -s 使 zxfer 为每个复制的数据集拍摄快照。

最后,-n 标志会触发无操作模式。zxfer 程序不会传输或删除任何快照。相反,它会执行分析,并打印出如果你没有设置 -n ,它会做什么。

现在您已经完成了复制,相比之下,ZFS卷的问题似乎很容易解决。或者,也许不是…