如何*有效地*确定自上次快照以来 ZFS 数据集是否已更改为简单的是/否问题?

s-m*_*m-e 5 zfs snapshot

假设我有一个名为的池tank和一个名为的数据集data。还有至少一张datanamed 的快照last_snapshot

tank
tank/data
tank/data@last_snapshot
Run Code Online (Sandbox Code Playgroud)

确定数据集是否已更改的“慢”方法是检查 的输出diff,据我所知:

zfs diff tank/data@last_snapshot

它将显示自上次快照以来每个文件/文件夹对数据集的所有更改。如果有大量更改,此命令会产生大量输出并运行几秒钟甚至几分钟。

一种更快但(据我所知)不太可靠的方法是查看written数据集的属性:

tank/data written 72K -
tank/data@last_snapshot written 1,83G -
Run Code Online (Sandbox Code Playgroud)

如果written数据集(不是任何快照)的值介于 56 和 128k 之间,则数据集通常自上次/最近的快照以来没有被修改。这要快得多,但不明白为什么这个数字会变化如此之大,我不想依赖这种方法。

如何安全快速地提出是/否问题:自上次快照以来,数据集是否已更改/修改?


设计理念(背景):我确实有相当数量的数据集,它们很少会收到“重大”变化,比如每两周一次。每天制作一次快照并保留最后一次,例如 7 次,很快会导致丢失最后一次“重大”更改之前的状态。这就是我想的地方:如果有“重大”变化,让我们只制作快照并保留其中的最后 7 个。

Jim*_* L. 3

这是一个好问题,我现在能做的就是投赞成票。

在思考这个问题时,我尝试过的一些猜测途径是:

  • 再次对数据集进行快照,并比较createtxg两个快照的(“出生”)属性。在一次测试中,我很幸运并且具有连续的值(这意味着在创建 snapA 和创建 snapB 之间的过渡期间没有发生任何事务)。这个事实后来被证明毫无价值,因为进一步的研究告诉我,事务组在整个池中全局编号,而不是在每个文件系统中唯一编号。

  • createtxg将快照的值与文件系统的最新事务组进行比较。我不确定,但如果快照createtxg等于或高于文件系统的最新事务组,则可以推断快照创建本身是已提交到该文件系统的最新事务。我不确定这是否属实,但如果可以将快照createtxg与文件系统的最新快照进行比较txg以精确确定快照是否“原始”,那将是偶然的。

此时,我能提供的最佳答案是信任written文件系统的属性,但仅限于严格的参数范围内:

1)确保所有待处理的事务已提交到文件系统

sync; sleep 1; sync  # maybe I'm just being superstitious?
Run Code Online (Sandbox Code Playgroud)

2) 确保文件系统处于非活动状态(未安装)

zfs umount tank/data
Run Code Online (Sandbox Code Playgroud)

written3)使用以下-p标志查询属性的确切机器可解析值zfs list

zfs list -Hpo written tank/data
Run Code Online (Sandbox Code Playgroud)

在我推断快照是原始的之前,该数字必须恰好为 0。zfs如果我们仅从手册页的表面来看,“小”还不够好:

以下本机属性包含有关数据集的只读统计信息。这些属性既不能设置,也不能继承。除非另有说明,本机属性适用于所有数据集类型。
...

createtxg

在其中创建数据集的事务组 (txg)。createtxg书签与它们最初绑定的快照具有相同的内容。此属性适合对快照列表进行排序,例如增量发送和接收。
...

written

自上一个快照以来写入此数据集的引用空间量。

进一步的承诺是:

written@snapshot

自指定快照以来写入此数据集的引用空间量。这是此数据集引用但指定快照未引用的空间。

需要卸载文件系统,以便在您注意到该值为 0 并开始对该状态采取行动之间不存在竞争条件,而同时另一个进程即将写入文件系统并破坏您的聚会。

如果有人知道如何查询文件系统最近提交的事务组号,我有义务知道该方法。一些基本的谷歌搜索没有找到任何我认为有用的东西。

另一个有趣的属性是referenced快照的属性与其父文件系统的属性。

referenced

此数据集可访问的数据量,可能会也可能不会与池中的其他数据集共享。创建快照或克隆时,它最初引用与创建它的文件系统或快照相同的空间量,因为其内容是相同的。

然而,我的预感是这个属性也会导致错误的希望,因为文件系统和快照可能都引用 10G 数据,但它与磁盘上实际块中的 10G 不同,正如短语“可能或可能”所暗示的那样不被共享”。匹配referenced值似乎更像是必要条件而不是充分条件。

总而言之,带着很大的谦虚和不确定性,我认为人们必须坚持这个zfs list输出,然后才能假设快照是原始的:

# zfs create -o mountpoint=/root/test w541/test
# zfs snap w541/test@snap1
# zfs list -po written,written@snap1 w541/test
WRITTEN  WRITTEN@SNAP1
      0              0
Run Code Online (Sandbox Code Playgroud)

弄脏了快照,它就不再原始了:

# touch test/foo
# zfs list -po written,written@snap1 w541/test
WRITTEN  WRITTEN@SNAP1
  57344          57344
Run Code Online (Sandbox Code Playgroud)

将其滚回去,它又变得原始了:

# zfs rollback w541/test@snap1
# zfs list -po written,written@snap1 w541/test
WRITTEN  WRITTEN@SNAP1
      0              0
Run Code Online (Sandbox Code Playgroud)

但为了获得最高的完整性,在查询属性之前,应该卸载文件系统,也许需要卸载一段时间written

我将非常感谢任何人对任何错误的假设、疏忽或任何好心人提供的额外见解的纠正。