如何将整个zfs池单向镜像到另一个zfs池


16

我有一个zfs池,其中包含几个zvol和数据集,其中一些也是嵌套的。所有数据集和zvol均由zfs-auto-snapshot定期快照。所有数据集和zvol都具有一些手动创建的快照。

我已经设置了一个远程池,由于时间不足,通过zfs send -R在本地高速网络上进行的初始复制未完成(某些数据集丢失,某些数据集已过时或缺少快照)。

现在,该池实际上是通过慢速连接处于远程状态,我需要定期将远程池与本地池同步,这意味着本地池中存在的数据必须复制到远程池中,本地池中的数据必须从远程池中删除,并且必须通过“ zvols”,“ datasets”或“ snapshots”等数据从远程池中删除存在于远程池中但不在本地池中的数据。

如果我在使用rsync的两个常规文件系统之间执行此操作,则将是“ -axPHAX --delete”(这实际上是我备份某些系统所执行的操作)。

如何设置同步任务,以便远程池zvol和数据集(包括其快照)可以与本地zvol,数据集和快照同步?

由于ssh的低吞吐量性能,我想避免通过ssh进行传输;我更喜欢mbuffer或iscsi。


您是如何开始的zfs send -R ...?如果通过管道输出ssh,是否使用禁用了转义字符zfs send -R ... | ssh -e none ...
Andrew Henle

另外-您需要确保慢速连接具有足够的带宽以使远程副本保持最新状态。如果对本地系统所做的更改多于对远程系统的更改,则将永远无法使远程副本保持最新状态。采取增量zfs复制流并将其保存到文件。如果文件大于两次快照之间可以发送到远程站点的数据量,则您将永远不会跟上。 zfs send -R -i pool@snap1 pool@snap2 | gzip --fast > /output/file.gz
Andrew Henle

您也可以尝试使用此脚本自动执行此操作:github.com/psy0rz/zfs_autobackup/blob/master/README.md
edwin eefting

Answers:


12

免责声明:由于我从未使用过zvol,因此无法说出它们在复制方面是否与普通文件系统或快照有所不同。我认为他们是,但我不相信我的话。


您的问题实际上是多个问题,我尝试分别回答:

如何将完整的池复制/镜像到远程位置

您需要将任务分为两部分:首先,必须完成初始复制,然后再进行增量复制,只要您不弄乱复制快照即可。要启用增量复制,您需要保留最后的复制快照,可以删除之前的所有快照。如果删除以前的快照,zfs recv将抱怨并中止复制。在这种情况下,您必须重新开始,因此请不要这样做。

如果您只需要正确的选项,它们是:

  • zfs send
    • -R:在给定的池或数据集下发送所有内容(递归复制,一直需要,包括-p)。同样,在接收时,所有已删除的源快照也会在目标上被删除。
    • -I:包括最后一个复制快照和当前复制快照之间的所有中间快照(仅增量发送需要)
  • zfs recv
    • -F:扩展目标池,包括删除在源上删除的现有数据集
    • -d:丢弃源池的名称,并将其替换为目标池的名称(其余文件系统路径将保留,并且在需要时也会创建)
    • -u:不要在目标上挂载文件系统

如果您希望使用完整的示例,请使用以下小脚本:

#!/bin/sh

# Setup/variables:

# Each snapshot name must be unique, timestamp is a good choice.
# You can also use Solaris date, but I don't know the correct syntax.
snapshot_string=DO_NOT_DELETE_remote_replication_
timestamp=$(/usr/gnu/bin/date '+%Y%m%d%H%M%S')
source_pool=tank
destination_pool=tank
new_snap="$source_pool"@"$snapshot_string""$timestamp"
destination_host=remotehostname

# Initial send:

# Create first recursive snapshot of the whole pool.
zfs snapshot -r "$new_snap"
# Initial replication via SSH.
zfs send -R "$new_snap" | ssh "$destination_host" zfs recv -Fdu "$destination_pool"

# Incremental sends:

# Get old snapshot name.
old_snap=$(zfs list -H -o name -t snapshot -r "$source_pool" | grep "$source_pool"@"$snapshot_string" | tail --lines=1)
# Create new recursive snapshot of the whole pool.
zfs snapshot -r "$new_snap"
# Incremental replication via SSH.
zfs send -R -I "$old_snap" "$new_snap" | ssh "$destination_host" zfs recv -Fdu "$destination_pool"
# Delete older snaps on the local source (grep -v inverts the selection)
delete_from=$(zfs list -H -o name -t snapshot -r "$source_pool" | grep "$snapshot_string" | grep -v "$timestamp")
for snap in $delete_from; do
    zfs destroy "$snap"
done

使用比SSH更快的功能

如果您具有足够安全的连接(例如IPSec或OpenVPN隧道),并且仅在发送方和接收方之间存在一个单独的VLAN,则可以从SSH切换到未加密的替代方案,如此处所述的 mbuffer ,或者可以将SSH与弱/无加密一起使用并禁用了压缩功能,有关详细信息,请参见此处。还有一个网站关于重新编译SSH的速度要快得多,但是不幸的是,我不记得URL了-如果找到它,我会稍后对其进行编辑。

对于非常大的数据集和缓慢的连接,这对于通过硬盘进行首次传输(使用加密磁盘存储zpool并通过快递,邮件或亲自将其密封包装)也很有用。由于传输方法对于send / recv无关紧要,您可以将所有内容通过管道传输到磁盘,导出池,将磁盘发送到其目的地,导入池,然后通过SSH传输所有增量发送。

快照混乱的问题

如前所述,如果删除/修改复制快照,则会收到错误消息

cannot send 'pool/fs@name': not an earlier snapshot from the same fs

这意味着您的命令错误或处于不一致状态,必须删除快照并重新开始。

这有几个负面影响:

  1. 在成功传输新的复制快照之前,您无法删除复制快照。由于这些复制快照包括所有其他(较旧)快照的状态,因此只有复制完成后,才会回收已删除文件和快照的空白空间。这可能会导致池上出现临时或永久空间问题,您只能通过重新启动或完成完整的复制过程来解决此问题。
  2. 您将拥有许多其他快照,这会减慢list命令的速度(在已修复此问题的Oracle Solaris 11上除外)。
  3. 您可能需要保护快照以防(意外)删除,但脚本本身除外。

对于这些问题,存在一种可能的解决方案,但是我自己还没有尝试过。您可以使用zfs bookmarkOpenSolaris / illumos中专门为此任务创建的一项新功能。这将使您摆脱快照管理。唯一的缺点是目前,它仅适用于单个数据集,而不适用于递归。您将必须保存所有旧数据集和新数据集的列表,然后在它们上循环,添加书签,发送和接收它们,然后更新列表(或小型数据库,如果您愿意)。

如果您尝试使用书签路线,我很想听听它如何为您服务!


非常感谢您提供详细的答案。我只是发送..正在接收zpool
抖动

1
不错的脚本。我将添加-d 1到这两个zfs list命令中以限制搜索深度(无需在池名称下方进行搜索)。这样可以避免在具有大量快照的池上长时间延迟(例如,我的“备份”池具有320000个快照,zfs list -r -t snapshot backup运行需要13分钟。使用只需0.06秒-d 1)。然后zfs destroy,for循环中的命令需要该-r选项以递归方式删除具有相同快照名称的所有快照。
cas

5

就个人而言,我会为自己列出远程服务器上没有最新快照的zvol,数据集等,然后使用来更新这些快照zfs send,即使这很耗时并且使用很多带宽。

然后,我可以zfs send从那时起继续使用,而不必编写自己的同步代码来重新发明轮子。rsync对于较旧的文件系统来说很好,但zfs send对zfs则更好。它确切知道快照中哪些块已更改,发送它们,而rsync必须比较本地和远程服务器之间的单个文件和/或时间戳。同样适用于btrfs send对BTRFS池。

如果只有少量快照需要更新,则可以手动完成。否则,要自动执行此操作,您需要一个最新的本地快照与远程快照的列表,以及一个脚本来比较版本,然后比较zfs sendrmeote服务器上已过期的本地快照。

如果您只关心每个数据集的最新快照,那就足够了。如果您关心以前的所有快照,显然您的脚本也将不得不处理它们……这将使很多事情变得更加复杂。在某些情况下,您可能必须在远程服务器上回滚,以便可以重新发送中间/丢失的快照。

如果您想要与远程服务器的安全连接,那么您实际上别无选择,只能使用ssh-或建立带有openvpn或某些东西并使用的隧道netcat


怎样使用Zrep?bolthole.com/solaris/zrep
XDG

不知道,从来没有用过。看起来这将是一个很好的答案,尽管如果有人进行一些研究和测试并将其写下来(这是一个提示)。
cas

我已经在Ubuntu(Linux上的ZFS)上对其进行了测试,但不适用于更深的数据集(容器/某物/某物)。我正在使用此端口进行shell 链接。递归标志export ZREP_R=-R根本不起作用。:(
Xdg

1

看一下FreeBSD上的“ zrepl”,它可以使您以及任何人的生活变得更加轻松。它是几天前在渥太华举行的BSDCan2018大会上提出的。它看起来很有希望,可能会解决您的问题



问题中的问题是:“如何设置同步任务,以便远程池zvol和数据集(包括其快照)可以与本地zvol,数据集和快照同步?”
杰夫·谢勒

0

zrep是一个不错的多合一解决方案,并且具有有关如何获得比单纯的SSH传输更快的传输的文档和说明。

https://github.com/bolthole/zrep

它也是跨平台的:在linux,freebsd和solaris / illumos上受支持



1
问题中的问题是:“如何设置同步任务,以便远程池zvol和数据集(包括其快照)可以与本地zvol,数据集和快照同步?”
杰夫·谢勒

杰夫,您是否建议最好的“答案”是从zrep文档中剪切n粘贴位,而不是仅仅引用zrep?
菲利普·布朗

1
我不知道最佳答案是什么,但是链接到软件并不是解决方案。实际上已经提到过。该问题问:“如何设置同步任务,以便远程池zvol和数据集(包括其快照)可以与本地zvol,数据集和快照同步?”
杰夫·谢勒

是的,这就是问题。但是,要完成WELL任务,不仅需要在此处的网页上进行大量书面说明,而且还需要做很多其他工作。这就是为什么zrep是2000行的shellscript。即使要删除原来问题根本不需要的所有部分,也需要数百行脚本才能很好地完成它。
菲利普·布朗
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.