ZFS 快照通过写时复制引用保留某一时点的数据集视图,不需要把全部数据另复制一遍。只要还有引用需要旧块,它们就继续保留。但创建仍涉及元数据与同步工作,不能承诺零分配,也不能把在提示符重画之前返回当作实测保证。本次没有运行 ZFS,保留文件中也未找到原文所称实验的原始输出,所以数值与运行效果必须单独限定来源。

这样的历史适合本地恢复,但 tank/data 的快照仍位于同一个池。让池不可用的故障,也可能让全部快照不可用。这描述的是共享故障边界,不是断言每次控制器故障都会原子地毁掉所有块。独立备份或复制还需要自己的保留策略及恢复验证,不能仅因另一处存在相同名字,就宣布已经获得完整灾难恢复能力。

为一个一致的树命名

快照原子地捕获数据集的文件系统状态;递归 -r 会让后代数据集在同一时刻建立快照。不递归时,子数据集被遗漏,并不是自动晚一点另拍一份。文件系统一致不等于应用检查点:数据库缓冲、日志以及选定数据集之外的文件,仍需遵循应用支持的备份或崩溃恢复流程。必须协调所有必要部分,才能把整组状态作为可恢复对象。

tank/data@daily-2026-09-16 这样的名字可以辅助保留策略,还应结合创建时间、属性与备份记录;名字本身不是删除资格的证明。zfs list -t snapshot -o name,used,refer,creation -s creation 用于观察快照及空间统计,真正清理之前还要检查依赖和 hold。自动命名也可以被可靠管理,关键是保留规则有明确、可追溯的依据。

空间在哪里:zfs list -o space

zfs list -o space tank/data 选择 NAME、AVAIL、USED、USEDSNAP、USEDDS、USEDREFRESERV 与 USEDCHILD,不包含 REFER。USED 分解为四项 used-by 类别,不能写成 REFER 加 USEDSNAP。REFER 表示数据集可访问的数据,其中也可能有共享块。单份快照的 USED 统计其独有引用,删除其他快照还会改变这个值,所以逐份相加不等于整体可回收空间。

原文三十份快照、六十四 MiB 数据集以及每日两 MiB 变化的数字,没有找回对应 ZFS 运行轨迹。六十 MiB 与一千九百二十 MiB 的对比只能当作示意算术,不能作为真实分配结论。元数据、压缩、块尺寸、共享关系及确切保留时间线都会影响成本。新快照独占很少,并不代表整组历史没有阻止大量空间回收。

hold、diff 与版本对比

用户 hold 会阻止销毁,直到明确释放。zfs hold keep tank/data@daily-2026-09-16 设置一个标签;zfs holds tank/data@daily-2026-09-16 检查它,zfs release keep tank/data@daily-2026-09-16 释放该标签。hold 可保护传输中的快照,但克隆源依赖是另一种关系,不一定显示成具名 hold 标签。释放前要弄清依赖的任务,而不是看到忙就盲目取消保护。

zfs diff tank/data@daily-2026-09-15 tank/data@daily-2026-09-16 比较仍保留的两个版本,报告新建、删除、修改与重命名路径。文件系统快照会按需挂载到 .zfs/snapshot/<name> 之下,snapdir=visible 让目录出现在列表里。读取旧文件与破坏性回滚整个数据集是不同恢复选择,两者本身都没有证明应用业务状态正确。

坏掉的样子

成功发送并接收到独立保护的存储,才可能在源池丢失后保留数据。所示增量传输要求目标已存在,而且最近快照匹配发送基线;只有增量流不构成完整独立备份。同机第二个池仍可能共用电源、控制器或管理员权限,因此不能只数池的个数判断隔离。必须核对接收内容并演练可用还原,才能说明它抵御了哪些故障。

USEDSNAP 上升应触发容量与保留检查,但池占用超过百分之八十不是统一的写失败阈值,还要观察配额、预留及实际可用空间。克隆依赖源快照,删除源或回滚越过较新依赖时需要有意识地处理关系。回滚会丢弃较新数据,而销毁克隆并非唯一恢复策略。可以选择恢复文件或另建恢复数据集,不应把破坏性递归操作当作自动下一步。

ZFS 快照谱系、克隆依赖、用户 hold 与 USED 统计分开说明,并保留回滚及独立接收的边界。
ZFS 历史存在依赖:机制图。

快速验证

以下独立运行的 Bash 配方尚未执行。它要求独占控制的一次性数据集、已存在的源快照,以及此前已从基线完整接收的目标。目标自基线以来必须未被修改,并挂载在绑定路径;路径中不能有中间挂载或符号链接,所用 hold 标签必须尚未占用。创建目标时点的源快照前,先在源数据集中准备普通文件 probe.txt,并把可信的外部预期副本放到 expected 路径。列表递归检查快照,但传输只覆盖 tank/data 本身,不包含后代数据集;不能把递归列出误当成递归复制。

(
  set -euo pipefail
  src='tank/data'
  dst='backup/data'
  base='daily-2026-09-15'
  next='daily-2026-09-16'
  tag='example-transfer'
  mount='/mnt/zfs-lab/received'
  expected='/mnt/zfs-lab/expected-v2.txt'

  zfs list -r -t snapshot -o name,used,refer,creation -s creation "$src" "$dst"
  zfs list -o name,avail,used,usedsnap,usedds,usedrefreserv,usedchild,refer "$src"
  zfs holds "$src@$base" "$src@$next"
  zfs diff "$src@$base" "$src@$next"

  latest=$(zfs list -H -r -t snapshot -o name -s createtxg "$dst" |
    awk -F@ -v dataset="$dst" '$1 == dataset { last=$0 } END { print last }')
  test "$latest" = "$dst@$base"
  source_guid=$(zfs get -Hp -o value guid "$src@$base")
  target_guid=$(zfs get -Hp -o value guid "$dst@$base")
  test -n "$source_guid"
  test "$source_guid" = "$target_guid"
  target_mount=$(zfs get -H -o value mountpoint "$dst")
  target_mounted=$(zfs get -H -o value mounted "$dst")
  test "$target_mount" = "$mount"
  test "$target_mounted" = yes
  test -f "$expected"
  test ! -L "$expected"

  zfs hold "$tag" "$src@$base" "$src@$next"
  zfs send -i "$src@$base" "$src@$next" | zfs receive "$dst"
  source_guid=$(zfs get -Hp -o value guid "$src@$next")
  target_guid=$(zfs get -Hp -o value guid "$dst@$next")
  test -n "$source_guid"
  test "$source_guid" = "$target_guid"
  test -f "$mount/.zfs/snapshot/$next/probe.txt"
  test ! -L "$mount/.zfs/snapshot/$next/probe.txt"
  cmp -- "$expected" "$mount/.zfs/snapshot/$next/probe.txt"
)

目标最近快照及基线 GUID 必须匹配,仅有相同名字不够。断言失败会停止子 shell,pipefail 会暴露管道任一端的失败。接收后 GUID 和测试文件字节一致,仍不能证明完整应用可还原:必须另行核对完整清单、元数据与应用恢复。无论成功或失败,已创建的 hold 都保留;完成验证与依赖检查后,仅用 zfs release example-transfer tank/data@daily-2026-09-15 tank/data@daily-2026-09-16 释放本实验标签。示例不包含强制回滚或自动清理,存储运行与完整恢复验证仍暂缓。

来源

  • zfs-snapshot(8),快照创建语义与递归快照,已核验 2026-09-16。
  • zfs-list(8),space 列集与独立的 REFER 属性,已核验 2026-09-16。
  • zfs-hold(8),hold、zfs holds 以及销毁返回的 EBUSY,已核验 2026-09-16。
  • zfs-send(8),增量发送流及其基线快照要求,已核验 2026-09-16。
  • zfsprops(7),used-by 分解、共享引用、配额与预留,已核验 2026-10-18。
  • zfs-clone(8),克隆对源快照的依赖,已核验 2026-10-18。
  • zfs-rollback(8),较新数据丢弃及依赖克隆处理,已核验 2026-10-18。
  • zfs-receive(8),增量接收要求匹配目标基线,已核验 2026-10-18。
  • PostgreSQL filesystem backup,一致快照范围、WAL 与多卷恢复要求,已核验 2026-10-18。
  • ZFS concepts,克隆对源快照的依赖与共享存储边界,已核验 2026-10-18。
  • zfs-get(8),用于 GUID 与挂载点检查的精确属性读取,已核验 2026-10-19。