用 FreeBSD ZFS 快照完成全量与增量复制

原文来自 FreeBSD 官方手册:The Z File System (ZFS),作者为 The FreeBSD Documentation Project。本文按既定研究范围,选编当前第 23.4.6 节快照管理与第 23.4.10 节复制及相关说明,形成一个完整的本机双池复制流程。2026 年 10 月 05 日读取的手册首页覆盖 FreeBSD 15.1、14.4、13.5,并提醒部分章节可能过时;章节编号和命令特性以当前安装版本为准。

ZFS 快照可以保存一个时间点的数据集状态,zfs send 把快照变成数据流,zfs receive 再把流还原成目标数据集。第一次建立全量副本,随后根据两端共有的快照发送变化,可以减少重复传输。这个机制提供复制能力,故障切换仍需要管理员安排。

操作范围:本稿假定两个独立池 mypool 与 backup 已经正确创建,示例池名只用于解释。没有格式化磁盘、创建池或使用生产设备的步骤;所有命令只做静态审阅,未实际执行。

先将mypool的replica1全量接收到backup/mypool,再以双方相同的replica1为起点,把replica2增量发送到目标;快照后的新写入不在副本中。
原创步骤示意图:全量复制建立共同起点,增量复制只传送两个快照之间的变化。

快照保存什么,空间又花在哪里

快照是数据集在某一时刻的只读视图,覆盖该数据集内的文件、目录、权限和相关状态。ZFS 的写时复制机制会把新内容写入新块,而快照继续引用旧块,因此建立快照很快,起初几乎不增加数据空间。随后活动数据被改写或删除时,快照仍需保留它引用的旧块,空间占用会增长。

快照以整个数据集为单位,不能只对普通目录或单个文件建立独立 ZFS 快照。zfs snapshot -r 可以为数据集及其子数据集创建同名快照,提供同一时刻的文件系统视图。编辑补充:这不自动替代数据库或应用所需的事务协调、日志刷新与一致性备份流程。

同池快照仍然依赖同一组存储设备;池丢失时,它不能变成独立副本。把数据复制到另一个池可以降低单池故障风险,但本机的两块存储仍可能同时受盗窃、火灾、供电故障或误操作影响,本机副本不能冒充异地备份。

首先分清池、根数据集和子数据集

zpool 管理存储池,zfs 管理池内数据集。池名 mypool 同时也是根数据集名;执行 zfs snapshot mypool@replica1 并不等于递归快照所有后代。

本稿基础流程复制 mypool 这个指定数据集。若实际文件位于 mypool/home、mypool/database 等独立子数据集,它们不会因为路径看起来位于同一池下面就自动进入普通发送流。先列出层级,确认备份边界:

zpool list
zpool status mypool
zpool status backup
zfs list -r mypool backup

核对池是否正常、目标可用空间是否足够、源数据具体位于哪个数据集。首次全量接收应使用新的目标,例如尚不存在的 backup/mypool;不要对已有业务数据集尝试“强制覆盖看看”。原指南说明只能复制到空目标,而 OpenZFS 接收手册进一步说明全量流会建立新文件系统。

原文容量表是示例环境的历史输出,不同演示中的数值也不完全相同。本稿不把这些数值复制成读者机器的容量预期,更不把它们当作性能测试。

创建第一个快照

zfs snapshot mypool@replica1
zfs list -t snapshot -r mypool

快照名称由数据集名、@ 和快照名组成。普通 zfs list 不列出快照,需加 -t snapshot;-t all 会同时显示文件系统与快照。只读快照没有通常意义上的可写可用空间,也不会像普通文件系统一样在列表中直接显示挂载路径。

复制的内容固定在 replica1 这一时刻。创建快照之后写入源数据集的新数据,不会偷偷进入本次发送;它必须等后续快照和增量复制。

发送流不是终端文本,也不只是快照的 USED 数字

zfs send 输出二进制流,应该管道给接收端,或者重定向到文件。原文直接向终端发送会报 Stream can not be written to a terminal。全量流包含该快照引用的数据,不能根据快照的 USED 很小甚至为零,就以为传输也几乎没有内容。

编辑补充:可以先用官方手册支持的 dry run 查看发送估算,它不会生成实际发送流:

zfs send -nv mypool@replica1

原文也展示过把流保存为备份池上的普通文件。文件流本身还不是可浏览的文件系统,需要以后再经 zfs receive 还原。重定向运算符 > 会覆盖已有同名文件,实际使用必须确认唯一文件名、备份池真实挂载位置和容量,不能盲目复用原例路径。本文使用管道接收路线。

全量接收到独立目标池

原文的核心命令是将 zfs send -v mypool@replica1 管道到 zfs receive backup/mypool。下面的编辑调整只增加接收参数 -u,让接收完成后暂不自动挂载,便于先检查属性与路径:

zfs send -v mypool@replica1 | zfs receive -u backup/mypool

-v 显示发送信息和进度;-u 的含义见 OpenZFS zfs-receive(8)。这些选项的含义经过静态核对,但这里没有真实传输日志。

完成后,分别核对数据集、快照和挂载属性:

zfs list -r backup/mypool
zfs list -t snapshot -r backup/mypool
zfs get mountpoint,canmount,mounted,readonly backup/mypool

预期检查对象是目标数据集及 backup/mypool@replica1,不是只看管道有没有输出错误。编辑补充:管道中发送端与接收端都可能失败,脚本化时应捕获两端状态;仅取某个 shell 默认返回的最后一个命令状态,不足以证明整条链路成功。

核对共同起点:同名不代表同一个快照

增量复制依赖双方真正共有的快照。手工在两个池各建一个叫 replica1 的快照,不会让它们成为相同起点。编辑补充:OpenZFS zfsprops(7) 明确说明,快照经发送接收到另一池后 GUID 保持相同,可以据此核对跨池身份:

zfs get guid mypool@replica1 backup/mypool@replica1

这里比较的是快照的 GUID,而不是父文件系统的 GUID。匹配只验证复制链的身份关联,不能替代文件可读性、应用恢复能力和介质健康检查。

创建新快照,再发送增量

源数据正常发生变化后,创建第二个快照:

zfs snapshot mypool@replica2
zfs list -t snapshot -r mypool

用 -i 指定较早的起点和较新的终点。以下仍保留前面增加的 -u:

zfs send -v -i mypool@replica1 mypool@replica2 | zfs receive -u backup/mypool

这次流表示从 replica1 到 replica2 的变化,而不是重发整份数据。接收目标必须已经存在,而且其最新快照要与这次增量起点匹配。接收端在基准之后被写入、出现不一致的快照历史或缺少共同起点,都可能使正常接收失败。

不要把失败当作加 -F 的理由。强制接收可能先回滚目标,在某些增量复制流中还会删除发送端不存在的快照和数据集;必须先查明分歧并保存目标上需要保留的数据。

复制后核对两端是否均出现 replica2,并验证新快照身份:

zfs list -t snapshot -r mypool backup/mypool
zfs get guid mypool@replica2 backup/mypool@replica2
zpool status backup

接收端现在保存的是第二个快照时刻的副本,replica2 之后的新写入仍不在其中。原文展示增量比全量传送更少的数据,但实际节省多少取决于工作负载、块变化、压缩和选项,本稿没有测量时间或字节数。

用差异、属性和恢复演练检查结果

原手册的 zfs diff 可以比较快照与活动数据集,或比较两个快照。第一列符号分别表示新增 +、删除 -、修改 M 和重命名 R。结合本稿快照名,可使用:

zfs diff mypool@replica1 mypool@replica2

这能帮助理解发生了哪些文件路径变化,但它不是对整份备份做独立字节校验,更不是数据库恢复演练。在隔离的挂载路径上验证代表性文件、权限与应用恢复,是确认备份可用的另一层检查。由于本文加了 -u,要先核对并安排安全挂载位置,不能假定目录已经可浏览。

快照中的单个文件可以通过数据集挂载点下的 .zfs/snapshot/快照名/ 读取。默认 snapdir=hidden 时普通目录列表可能不显示 .zfs,但显式访问仍可用。把需要的文件复制到安全的新位置,比为了找回一个文件就回滚整个数据集更容易控制影响;复制回现有文件位置仍可能覆盖当前版本。

属性与子数据集需要显式选择

发送选项 原手册说明 需要核对的边界
-p 包含数据集属性,例如压缩、配额和挂载点 源挂载路径或共享属性不一定适用于目标
-R 生成复制包,包含数据集、子数据集、相关快照、克隆和属性,隐含 -p 要配合正确的递归快照与接收层级;范围比基础示例大得多
-L 允许流携带大于 128 KB 的块 接收池要支持相应特性
-e 使用嵌入块表示,使符合条件的小块流更紧凑 必须考虑接收端特性与加密限制
-c 按压缩后的形式发送已压缩块 支持的压缩特性必须兼容
-w 对加密数据集发送磁盘上的原始加密形式 与普通发送不同;恢复密钥和原始增量链需单独管理

当前手册提到现代池可考虑组合 -Lec,但接收端必须支持流使用的每个特性。本文没有将这些选项无条件塞入基础命令,因为复制范围、加密形式和版本兼容性需要分别确定。参数完整定义见 zfs-send(8),master 文档也可能领先于已安装版本,应同时看本机手册。

保护增量链,避免把清理变成重做全量

原手册说明,zfs hold 可以给快照加一个自定义标签,阻止它被销毁。共有起点正适合受到保护:

zfs hold replication-base mypool@replica1
zfs hold replication-base backup/mypool@replica1
zfs holds mypool@replica1
zfs holds backup/mypool@replica1

这是依据原文 hold 机制改写的编辑示例,没有实际添加标签。每一端的持有标记要独立管理;新的共同快照验证成功后,再决定旧起点何时可以退出保留策略。解除 hold 只会移除保护,不等同于自动删除快照。

书签提供另一种选择:它记录快照的时间点和增量所需信息,却不保留该快照的数据块。源端可以在已有可靠副本后使用书签作为后续增量起点,但接收端仍须保留对应快照。书签无法挂载、回滚或找回文件,因此不能把它当作备份。初次建立流程时,保留两端共同快照更容易核查。

中断、回滚与强制操作的边界

当前手册还讲解可恢复接收:zfs receive -s 可以保存未完成状态,receive_resume_token 属性提供给 zfs send -t 用于继续传输。未完成状态占用目标空间,并会影响其他接收。zfs receive -A 会放弃并删除这份部分状态;它不是日常检查命令。使用之前应确认安装版本和目标池特性。

快照回滚会丢弃该数据集中快照之后的状态;zfs rollback -r 还会删除阻挡回滚的较新快照。zfs destroy 则直接销毁指定对象,递归选项会扩大范围。原手册有配套的删除演示,本稿只解释风险,不将这些命令放进正常复制步骤。若只是核查计划删除的对象,原文介绍的 -n -v 可以用于预览销毁范围,但本次也没有执行。

原章另有 SSH 传输、权限委派和纠错接收内容。本稿限定本机双池,不配置远程账号、不打开 root 登录,也不把普通未加密发送流描述成网络安全通道。当前纠错接收说明要求 OpenZFS 2.2(首次随 FreeBSD 14.0 提供),只能修复流中已有的数据块,不能替代完整恢复,也不能修复任意元数据或快照后的数据。

自动化应建立在全量、增量、错误处理、保留策略和恢复检查均清楚之后。原手册提到可以用 cron 定时发送与接收,但本文没有创建计划任务,复制也不构成自动故障切换。

版本、静态审核与来源

本稿的命令只经静态对照:没有创建快照、挂载数据集、接收流、添加 hold、回滚、销毁、运行 scrub 或读取实际用户文件。可见示例不含硬编码秘密或动态执行输入;没有发现这些问题不意味着没有漏洞。实际权限、存储布局、故障恢复与性能均未测试。

相对原文的主要修改是:为接收添加 -u;加入只读状态、GUID、属性核对和 dry run 估算;省略破坏性演示链,把损失风险直接说明。手册全文原始页面与所用小节文本随稿保存,本文不声称翻译整本 ZFS 管理手册。

原文版权:Copyright © 1995–2026 The FreeBSD Documentation Project。相关来源:FreeBSD Handbook 首页与版本说明、ZFS 章节、FreeBSD Documentation License。中文选编与原创示意图:未完纪。

FreeBSD 文档许可声明

以下保留文档许可要求的版权、条件与免责声明。中文正文中的编辑修改不代表 FreeBSD 项目背书。

Copyright 1994-2026 The FreeBSD Project.

Redistribution and use in source (AsciiDoc) and ‘compiled’ forms (HTML, PDF, EPUB and so forth) with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code (AsciiDoc) must retain the above copyright notice, this list of conditions and the following disclaimer as the first lines of this file unmodified.
  2. Redistributions in compiled form (Converted to PDF, EPUB and other formats) must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

THIS DOCUMENTATION IS PROVIDED BY THE FREEBSD DOCUMENTATION PROJECT "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.

IN NO EVENT SHALL THE FREEBSD DOCUMENTATION PROJECT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容