dm-clone¶
引言¶
dm-clone 是一個裝置對映器目標,它將現有隻讀源裝置一對一複製到可寫目標裝置:它呈現一個虛擬塊裝置,使所有資料立即可見,並相應地重定向讀寫操作。
dm-clone 的主要用例是將一個可能遠端、高延遲、只讀的歸檔型塊裝置克隆到一個可寫、快速、主用型裝置中,以實現快速、低延遲的 I/O。克隆裝置會立即可見/可掛載,並且源裝置到目標裝置的複製會在後臺與使用者 I/O 並行進行。
例如,可以從透過網路儲存協議(NBD、光纖通道、iSCSI、AoE 等)訪問的只讀副本中恢復應用程式備份到本地 SSD 或 NVMe 裝置,並立即開始使用該裝置,而無需等待恢復完成。
克隆完成後,可以完全移除 dm-clone 表,並替換為(例如)直接對映到目標裝置的線性表。
dm-clone 目標複用了精簡配置(thin-provisioning)目標所使用的元資料庫。
術語表¶
- 資料填充(Hydration)
用源裝置相同區域的資料填充目標裝置某個區域的過程,即從源裝置向目標裝置複製該區域。
一旦某個區域被資料填充,我們就會將所有相關的 I/O 重定向到目標裝置。
設計¶
子裝置¶
該目標透過傳入三個裝置(以及稍後詳述的其他引數)來構建
源裝置 - 被克隆的只讀裝置,也是資料填充的來源。
目標裝置 - 資料填充的目標,它將成為源裝置的克隆。
一個小型元資料裝置 - 它記錄目標裝置中哪些區域已有效,即哪些區域已完成資料填充,或已透過使用者 I/O 直接寫入。
目標裝置的大小必須至少等於源裝置的大小。
區域¶
dm-clone 將源裝置和目標裝置劃分為固定大小的區域。區域是資料填充的單位,即從源裝置複製到目標裝置的資料的最小量。
首次建立 dm-clone 裝置時,區域大小是可配置的。推薦的區域大小與檔案系統塊大小相同,通常為 4KB。區域大小必須介於 8 個扇區(4KB)和 2097152 個扇區(1GB)之間,並且是 2 的冪。
對已填充區域的讀寫操作由目標裝置提供服務。
對尚未填充區域的讀取操作直接由源裝置提供服務。
對尚未填充區域的寫入操作將被延遲,直到相應的區域已填充並且該區域的資料填充立即開始。
請注意,大小等於區域大小的寫入請求將跳過從源裝置複製相應區域,直接覆蓋目標裝置的區域。
丟棄¶
dm-clone 將針對尚未填充範圍的丟棄請求解釋為跳過該請求所覆蓋區域資料填充的提示,即它跳過將區域資料從源裝置複製到目標裝置,而只更新其元資料。
如果目標裝置支援丟棄,則 dm-clone 預設會將其丟棄請求向下傳遞給目標裝置。
後臺資料填充¶
dm-clone 不斷地將資料從源裝置複製到目標裝置,直到整個裝置被複制完成。
將資料從源裝置複製到目標裝置會佔用頻寬。使用者可以設定一個節流閥來防止在任何時候發生超過一定量的資料複製。此外,dm-clone 會考慮流向裝置的 使用者 I/O 流量,並在有 I/O 正在進行時暫停後臺資料填充。
訊息 hydration_threshold <#regions> 可用於設定正在複製的最大區域數量,預設值為 1 個區域。
dm-clone 使用 dm-kcopyd 將源裝置的部分資料複製到目標裝置。預設情況下,我們發出的複製請求大小等於區域大小。訊息 hydration_batch_size <#regions> 可用於調整這些複製請求的大小。增加資料填充批處理大小會導致 dm-clone 嘗試將連續區域批次處理在一起,因此我們以這些區域的批次數量複製資料。
當目標裝置的資料填充完成後,將向用戶空間傳送一個 dm 事件。
更新磁碟元資料¶
每當寫入 FLUSH 或 FUA bio 時,磁碟元資料都會被提交。如果沒有此類請求,則每秒鐘會發生提交。這意味著 dm-clone 裝置的行為類似於具有易失性寫入快取的物理磁碟。如果斷電,您可能會丟失一些最近的寫入。無論發生任何崩潰,元資料都應始終保持一致。
目標介面¶
建構函式¶
clone <metadata dev> <destination dev> <source dev> <region size> [<#feature args> [<feature arg>]* [<#core args> [<core arg>]*]]
元資料裝置
儲存持久元資料的快速裝置
目標裝置
目標裝置,源將克隆到此裝置
源裝置
包含要克隆資料的只讀裝置
區域大小
區域大小(扇區為單位)
特性引數數量
已傳遞的特性引數數量
特性引數
`no_hydration` 或 `no_discard_passdown`
核心引數數量
傳遞給 dm-clone 的鍵/值對對應的偶數個引數
核心引數
傳遞給 dm-clone 的鍵/值對,例如 hydration_threshold 256
可選特性引數有
`no_hydration`
建立停用後臺資料填充的 dm-clone 例項
`no_discard_passdown`
停用將丟棄請求傳遞給目標裝置
可選核心引數有
`hydration_threshold <#regions>`
在後臺數據填充期間,在任何給定時間從源裝置複製到目標裝置的最大區域數量。
`hydration_batch_size <#regions>`
在後臺數據填充期間,嘗試將連續區域批次處理在一起,以便我們以多個區域為一批從源裝置複製資料到目標裝置。
狀態¶
<metadata block size> <#used metadata blocks>/<#total metadata blocks> <region size> <#hydrated regions>/<#total regions> <#hydrating regions> <#feature args> <feature args>* <#core args> <core args>* <clone metadata mode>
元資料塊大小
每個元資料塊的固定塊大小(扇區為單位)
已使用的元資料塊數量
已使用的元資料塊數量
元資料塊總數
元資料塊總數
區域大小
裝置的區域大小可配置(扇區為單位)
已填充區域數量
已完成資料填充的區域數量
區域總數
待填充區域總數
正在填充的區域數量
當前正在填充的區域數量
特性引數數量
後續特性引數數量
特性引數
特性引數,例如 no_hydration
核心引數數量
後續核心引數的偶數數量
核心引數
用於調整核心的鍵/值對,例如 hydration_threshold 256
克隆元資料模式
ro 表示只讀,rw 表示讀寫
在嚴重情況下,即使只讀模式也被認為不安全,則不允許進一步的 I/O,狀態將僅包含字串“Fail”。如果元資料模式發生更改,將向用戶空間傳送一個 dm 事件。
訊息¶
- `disable_hydration`
停用目標裝置的後臺資料填充。
- `enable_hydration`
啟用目標裝置的後臺資料填充。
- `hydration_threshold <#regions>`
設定後臺資料填充閾值。
- `hydration_batch_size <#regions>`
設定後臺資料填充批處理大小。
示例¶
克隆包含檔案系統的裝置¶
建立 dm-clone 裝置。
dmsetup create clone --table "0 1048576000 clone $metadata_dev $dest_dev \ $source_dev 8 1 no_hydration"
掛載裝置並修剪檔案系統。dm-clone 會解釋檔案系統傳送的丟棄請求,並且不會對未使用的空間進行資料填充。
mount /dev/mapper/clone /mnt/cloned-fs fstrim /mnt/cloned-fs
啟用目標裝置的後臺資料填充。
dmsetup message clone 0 enable_hydration
當資料填充完成後,我們可以用線性表替換 dm-clone 表。
dmsetup suspend clone dmsetup load clone --table "0 1048576000 linear $dest_dev 0" dmsetup resume clone
元資料裝置不再需要,可以安全地丟棄或重新用於其他目的。
已知問題¶
我們將對尚未填充區域的讀取操作重定向到源裝置。如果讀取源裝置具有高延遲,並且使用者反覆讀取相同區域,則此行為可能會降低效能。我們應該將這些讀取作為提示,以更快地填充相關區域。目前,我們依賴頁面快取來快取這些區域,因此希望我們不會多次從源裝置讀取它們。
在資料填充完成後,釋放核心記憶體資源,即跟蹤哪些區域已填充的點陣圖。
在後臺數據填充期間,如果我們未能讀取源裝置或寫入目標裝置,我們會列印一條錯誤訊息,但資料填充過程會無限期地繼續,直到成功。我們應該在多次失敗後停止後臺資料填充,併發出一個 dm 事件以供使用者空間注意。
為什麼不...?¶
在實現 dm-clone 之前,我們探索了以下替代方案
使用 dm-cache,其快取大小等於源裝置,並實現新的克隆策略
生成的快取裝置不是源裝置的一對一映象,因此一旦克隆完成,我們無法移除該快取裝置。
dm-cache 會寫入源裝置,這違反了我們關於源裝置必須被視為只讀的要求。
快取與克隆在語義上有所不同。
使用 dm-snapshot,其 COW 裝置等於源裝置
dm-snapshot 將其元資料儲存在 COW 裝置中,因此生成的裝置不是源裝置的一對一映象。
沒有後臺複製機制。
dm-snapshot 需要在待處理異常完成後提交其元資料,以確保快照一致性。在克隆的情況下,我們不需要如此嚴格,可以像 dm-thin 和 dm-cache 那樣,每次寫入 FLUSH 或 FUA bio 時,或定期提交元資料。這顯著提高了效能。
使用 dm-mirror:映象目標具有後臺複製/映象機制,但它會寫入所有映象,從而違反了我們關於源裝置必須被視為只讀的要求。
使用 dm-thin 的外部快照功能。這種方法是所有替代方案中最有前景的,因為精簡配置的卷是源裝置的一對一映象,並且處理對未配置/尚未克隆區域的讀寫方式與 dm-clone 相同。
然而
目前沒有後臺複製機制,儘管可以實現一個。
最重要的是,我們希望支援任意塊裝置作為克隆過程的目標,而不是將自己限制在精簡配置捲上。精簡配置存在固有的元資料開銷,用於維護精簡卷對映,這會顯著降低效能。
此外,克隆裝置不應強制使用精簡配置。另一方面,如果我們要使用精簡配置,我們只需將精簡邏輯卷(thin LV)用作 dm-clone 的目標裝置。