如何將整個 zfs 池單向鏡像到另一個 zfs 池

如何將整個 zfs 池單向鏡像到另一個 zfs 池

我有一個 zfs 池,其中包含多個 zvol 和資料集,其中一些也嵌套。所有資料集和 zvol 都會由 zfs-auto-snapshot 定期產生快照。所有資料集和 zvol 也有一些手動建立的快照。

我設定了一個遠端池,由於時間不足,透過 zfs send -R 透過本地高速網路進行的初始複製未完成(某些資料集遺失,某些資料集已過時或遺失快照)。

現在,池透過低速連接在物理上處於遠端狀態,我需要定期將遠端池與本地池同步,這意味著必須將本地池中存在的資料複製到遠端池,必須從遠端池中刪除來自本地池的數據,且遠端池中存在但本機池中不存在的資料必須從遠端池中刪除,資料意義為「zvols」、「資料集」或「快照」。

如果我使用 rsync 在兩個常規檔案系統之間執行此操作,則將是“-axPHAX --delete”(這就是我備份某些系統的實際操作)。

如何設定同步任務,以便遠端池 zvol 和資料集(包括其快照)可以與本機 zvol、資料集和快照同步?

我想避免透過 ssh 傳輸,因為 ssh 的吞吐量效能較低;我更喜歡 mbuffer 或 iscsi。

答案1

免責聲明:由於我從未使用過 zvols,因此我不能說它們在複製方面與普通檔案系統或快照是否有任何不同。我認為是的,但不要相信我的話。


你的問題其實是多個問題,我試著分開回答:

如何將完整池複製/鏡像到遠端位置

您需要將任務分為兩部分:首先,必須完成初始複製,然後可以進行增量複製,只要你不弄亂你的複製快照。要啟用增量複製,您需要保留最後的複製快照,之前的所有內容都可以刪除。如果刪除先前的快照,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並透過快遞、郵件或親自以密封包裝傳輸)。由於傳輸方法對於發送/接收並不重要,因此您可以將所有內容透過管道傳輸到磁碟,匯出池,將磁碟發送到其目的地,匯入池,然後透過 SSH 傳輸所有增量發送。

快照混亂的問題

如前所述,如果您刪除/修改複製快照,您將收到錯誤訊息

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

這意味著您的命令錯誤,或者您處於不一致的狀態,您必須刪除快照並重新開始。

這有幾個負面影響:

  1. 在成功傳輸新的複製快照之前,您無法刪除複製快照。由於這些複製快照包括所有其他(較舊)快照的狀態,因此只有在複製完成後才會回收已刪除檔案和快照的空白空間。這可能會導致池中出現臨時或永久的空間問題,您只能透過重新啟動或完成完整的複製過程來修復該問題。
  2. 您將擁有許多額外的快照,這會減慢 list 命令的速度(Oracle Solaris 11 除外,該問題已修復)。
  3. 您可能需要保護快照免於(意外)刪除,腳本本身除外。

這些問題有一個可能的解決方案,但我自己還沒有嘗試過。您可以使用zfs bookmarkOpenSolaris/illumos 中專門為此任務創建的新功能。這將使您擺脫快照管理的束縛。唯一的缺點是目前它僅適用於單一資料集,而不是遞歸的。您必須保存所有舊資料集和新資料集的列表,然後循環它們、添加書籤、發送和接收它們,然後更新列表(或小型資料庫,如果您願意)。

如果您嘗試書籤路線,我很想知道它對您來說效果如何!

答案2

就我個人而言,我會在遠端伺服器上為自己製作一個 zvol、資料集等的列表擁有最新的快照,然後使用 更新這些快照zfs send,即使這非常耗時且佔用大量頻寬。

然後我就可以繼續使用zfs send,而不必透過編寫自己的同步程式碼來重新發明輪子。rsync對於較舊的檔案系統很好,但zfs send對於 zfs 更好 - 它知道確切地快照中哪些區塊已更改並發送僅有的它們,而 rsync 必須比較本地和遠端伺服器之間的單一檔案和/或時間戳。這同樣適用於btrfs sendbtrfs 池。

如果您只有少量快照需要更新,則可以手動完成此操作。否則,要自動執行此操作,您需要最新的本機快照與遠端快照的列表,以及用於比較版本和zfs sendrmeote 伺服器上過期的本機快照的腳本。

如果您只關心每個資料集的最新快照,這就足夠了。如果您關心所有先前的快照,顯然您的腳本也必須處理它們......這會變得更加複雜。在某些情況下,您可能必須在遠端伺服器上回滾,以便可以重新傳送中間/遺失的快照。

如果您想要與遠端伺服器建立安全連接,您實際上別無選擇,只能使用ssh- 或可能使用 或其他東西建立隧道openvpn並使用netcat

答案3

看看 FreeBSD 上的“zrepl”,它可以讓您以及任何人的生活變得更加輕鬆。它於幾天前在渥太華舉行的 BSDCan2018 期間發布。它看起來很有前途,可能會解決您的問題

答案4

zrep 是一個很好的一體化解決方案,並且有文件+掛鉤如何獲得比普通 SSH 傳輸更快的傳輸

https://github.com/bolthole/zrep

它也是跨平台的:支援 linux、freebsd 和Solaris/illumos

相關內容