我有一个 zfs 池,其中包含多个 zvol 和数据集,其中一些还嵌套。zfs-auto-snapshot 定期对所有数据集和 zvol 进行快照。所有数据集和 zvol 也有一些手动创建的快照。
我已经设置了一个远程池,由于时间不够,通过 zfs send -R 在本地高速网络上的初始复制没有完成(一些数据集丢失,一些数据集已经过时或缺少快照)。
现在池通过慢速连接在物理上是远程的,我需要定期将远程池与本地池同步,这意味着必须将本地池中存在的数据复制到远程池,必须从远程池中删除本地池中的数据,并且存在于远程池中但不在本地池中的数据必须从远程池中删除,数据表示“zvols”、“数据集”或“快照”。
如果我使用 rsync 在两个常规文件系统之间执行此操作,它将是“-axPHAX --delete”(这就是我实际为备份某些系统所做的操作)。
如何设置同步任务,以便远程池 zvol 和数据集(包括它们的快照)可以与本地 zvol、数据集和快照同步?
我想避免通过 ssh 传输,因为 ssh 的吞吐量性能较低;我更喜欢 mbuffer 或 iscsi 。
use*_*391 16
免责声明:由于我从未使用过 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
Run Code Online (Sandbox Code Playgroud)
如果您有足够安全的连接,例如 IPSec 或 OpenVPN 隧道以及仅存在于发送方和接收方之间的单独 VLAN,您可以从 SSH 切换到未加密的替代方案,如此处所述的mbuffer ,或者您可以使用弱加密/无加密的 SSH和禁用压缩,详细说明here。还有一个网站关于重新编译 SSH 以使其更快,但不幸的是我不记得 URL - 如果我找到它,我会稍后编辑它。
对于非常大的数据集和较慢的连接,通过硬盘进行第一次传输(使用加密磁盘存储 zpool 并通过快递、邮件或亲自通过密封包传输)也可能有用。由于传输方法对于发送/接收无关紧要,您可以将所有内容通过管道传输到磁盘,导出池,将磁盘发送到其目的地,导入池,然后通过 SSH 传输所有增量发送。
如前所述,如果您删除/修改复制快照,您将收到错误消息
cannot send 'pool/fs@name': not an earlier snapshot from the same fs
Run Code Online (Sandbox Code Playgroud)
这意味着您的命令是错误的,或者您处于不一致的状态,您必须删除快照并重新开始。
这有几个负面影响:
这些问题存在一个可能的解决方案,但我自己没有尝试过。您可以使用zfs bookmark
OpenSolaris/illumos 中专门为此任务创建的新功能。这将使您摆脱快照管理。唯一的缺点是目前它只适用于单个数据集,而不是递归的。您必须保存所有旧数据集和新数据集的列表,然后遍历它们、添加书签、发送和接收它们,然后更新列表(或小型数据库,如果您愿意)。
如果您尝试书签路线,我很想听听它对您的效果如何!
就个人而言,我会让自己在远程服务器上列出没有最新快照的 zvol、数据集等,然后使用 将这些快照更新zfs send
,即使这很耗时并且使用很多的带宽。
然后我可以zfs send
从那时起继续使用,而不必通过编写自己的同步代码来重新发明轮子。rsync
对旧文件系统很好,但zfs send
对 zfs 更好——它确切地知道快照中哪些块发生了变化并只发送它们,而 rsync 必须比较本地和远程服务器之间的单个文件和/或时间戳。同样适用btrfs send
于 btrfs 池。
如果您只有少量快照需要更新,则可以手动完成。否则,要自动执行此操作,您需要一份最新本地快照与远程快照的列表,以及一个用于比较版本的脚本,然后zfs send
是 rmeote 服务器上过时的本地快照。
如果您只关心每个数据集的最新快照,这就足够了。如果您关心所有以前的快照,显然您的脚本也将不得不处理它们......这变得更加复杂。在某些情况下,您可能需要在远程服务器上回滚,以便重新发送中间/丢失的快照。
如果您想要与远程服务器建立安全连接,您真的别无选择,只能使用ssh
- 或者openvpn
使用netcat
.