精簡配置

簡介

本文件描述了一系列裝置對映器目標,它們共同實現了精簡配置和快照功能。

與之前的快照實現相比,此實現的主要亮點在於它允許在同一個資料捲上儲存多個虛擬裝置。這簡化了管理,並允許在卷之間共享資料,從而減少了磁碟使用量。

另一個重要特性是支援任意深度的遞迴快照(快照的快照的快照...)。之前的快照實現透過鏈式查詢表來完成此操作,因此效能是 O(深度)。這種新實現使用單一資料結構來避免隨著深度增加而出現的效能下降。然而,在某些情況下,碎片化可能仍然是一個問題。

元資料與資料儲存在單獨的裝置上,這為管理員提供了一些自由,例如可以:

  • 透過將元資料儲存在映象捲上,而將資料儲存在非映象捲上,從而提高元資料彈性。

  • 透過將元資料儲存在 SSD 上來提高效能。

狀態

這些目標被認為可以安全用於生產環境。但不同的使用場景將具有不同的效能特徵,例如由於資料卷的碎片化。

如果您發現此軟體效能不符合預期,請將詳細資訊傳送郵件至 dm-devel@redhat.com,我們將盡力為您改進。

用於檢查和修復元資料的使用者空間工具已完全開發,並可作為“thin_check”和“thin_repair”使用。提供這些實用程式的軟體包名稱因發行版而異(在 Red Hat 發行版上,它名為“device-mapper-persistent-data”)。

操作指南

本節描述了一些使用精簡配置的快速方法。它們使用 dmsetup 程式直接控制裝置對映器驅動。一旦新增支援,建議終端使用者使用更高級別的卷管理器,例如 LVM2。

池裝置

池裝置將元資料卷和資料卷連線在一起。它將 I/O 線性對映到資料卷,並透過兩種機制更新元資料:

  • 來自精簡目標的函式呼叫

  • 來自使用者空間的裝置對映器“訊息”,用於控制新虛擬裝置的建立等。

設定一個新的池裝置

設定池裝置需要一個有效的元資料裝置和一個數據裝置。如果您沒有現有的元資料裝置,可以透過將前 4KB 歸零來建立一個,以表示空的元資料。

dd if=/dev/zero of=$metadata_dev bs=4096 count=1

您需要的元資料量將根據精簡裝置之間共享的塊數(即透過快照)而異。如果共享量低於平均水平,您將需要一個比平均大小更大的元資料裝置。

作為指導,我們建議您將元資料裝置中使用的位元組數計算為 48 * $data_dev_size / $data_block_size,但如果結果較小,則向上取整到 2MB。如果您正在建立大量記錄大量更改的快照,您可能會發現需要增加此值。

支援的最大大小為 16GB:如果裝置更大,將發出警告,並且多餘的空間將不被使用。

重新載入池表

您可以重新載入池的表,事實上,當池空間不足時,就是透過這種方式調整池大小的。(注意:雖然目前不禁止在重新載入時指定不同的元資料裝置,但如果它沒有將 I/O 路由到與之前完全相同的磁碟位置,則會出現問題。)

使用現有池裝置

dmsetup create pool \
    --table "0 20971520 thin-pool $metadata_dev $data_dev \
             $data_block_size $low_water_mark"

$data_block_size 表示每次可分配的最小磁碟空間單位,以 512 位元組扇區為單位。$data_block_size 必須介於 128 (64KB) 和 2097152 (1GB) 之間,並且是 128 (64KB) 的倍數。薄池建立後,$data_block_size 無法更改。主要對精簡配置感興趣的使用者可能希望使用 1024 (512KB) 之類的值。進行大量快照的使用者可能希望使用 128 (64KB) 之類的值。如果您不將新分配的資料歸零,則建議使用 256000 (128MB) 左右的較大 $data_block_size。

$low_water_mark 以 $data_block_size 大小的塊表示。如果資料裝置上的可用空間低於此水平,將觸發一個 dm 事件,使用者空間守護程式應捕獲該事件,從而允許它擴充套件池裝置。只會傳送一個此類事件。

如果剛恢復的裝置的可用空間低於低水位標記,則不會觸發特殊事件。但是,恢復裝置總是會觸發一個事件;使用者空間守護程式在處理此事件時應驗證可用空間是否超過低水位標記。

元資料裝置的低水位標記在核心中維護,如果元資料裝置上的可用空間低於該標記,將觸發 dm 事件。

更新磁碟元資料

每次寫入 FLUSH 或 FUA bio 時,都會提交磁碟上的元資料。如果沒有此類請求,則每秒提交一次。這意味著精簡配置目標的行為類似於具有易失性寫入快取的物理磁碟。如果斷電,您可能會丟失最近的一些寫入。儘管發生任何崩潰,元資料應始終保持一致。

如果資料空間耗盡,池將根據配置(參見:error_if_no_space)報錯或排隊 I/O。如果元資料空間耗盡或元資料操作失敗:池將報錯 I/O,直到池離線並執行修復,以 1) 修復任何潛在的不一致性,以及 2) 清除強制修復的標誌。一旦池的元資料裝置修復,就可以調整大小,這將允許池恢復正常執行。請注意,如果池被標記為需要修復,則在執行修復之前,池的資料和元資料裝置無法調整大小。還應注意的是,當池的元資料空間耗盡時,當前元資料事務將被中止。鑑於池將快取其完成可能已向上層 I/O 層(例如檔案系統)確認的 I/O,因此強烈建議在需要修復池時對這些層執行一致性檢查(例如 fsck)。

精簡配置

  1. 建立新的精簡配置卷。

要建立一個新的精簡配置卷,您必須向一個活躍的池裝置傳送訊息,例如本例中的 /dev/mapper/pool。

dmsetup message /dev/mapper/pool 0 "create_thin 0"

這裡的“0”是卷的識別符號,一個 24 位數字。由呼叫者負責分配和管理這些識別符號。如果識別符號已被使用,訊息將因 -EEXIST 錯誤而失敗。

  1. 使用精簡配置卷。

精簡配置卷使用“thin”目標啟用。

dmsetup create thin --table "0 2097152 thin /dev/mapper/pool 0"

最後一個引數是 thinp 裝置的識別符號。

內部快照

  1. 建立內部快照。

快照透過向池傳送另一條訊息來建立。

注意:如果您希望建立快照的源裝置處於活動狀態,則必須在建立快照之前暫停它,以避免資料損壞。目前不強制執行此操作,因此請務必小心!

dmsetup suspend /dev/mapper/thin
dmsetup message /dev/mapper/pool 0 "create_snap 1 0"
dmsetup resume /dev/mapper/thin

這裡的“1”是卷的識別符號,一個 24 位數字。“0”是源裝置的識別符號。

  1. 使用內部快照。

一旦建立,使用者無需擔心源和快照之間的任何連線。事實上,快照與任何其他精簡配置裝置沒有區別,並且可以透過相同的方法對其自身進行快照。僅啟用其中一個完全合法,並且對同時啟用或刪除它們沒有順序要求。(這與傳統的裝置對映器快照不同。)

以與任何其他精簡配置卷完全相同的方式啟用它。

dmsetup create snap --table "0 2097152 thin /dev/mapper/pool 1"

外部快照

您可以使用外部**只讀**裝置作為精簡配置卷的源。對精簡裝置未分配區域的任何讀取都將傳遞到源裝置。寫入像往常一樣觸發新塊的分配。

一個用例是希望在精簡配置捲上執行虛擬機器的宿主機,但其基礎映象位於另一個裝置上(可能在多個虛擬機器之間共享)。

如果使用此技術,您絕不能寫入源裝置!當然,您可以寫入精簡裝置並對精簡捲進行內部快照。

  1. 建立外部裝置的快照

這與建立精簡裝置相同。在此階段您無需提及源裝置。

dmsetup message /dev/mapper/pool 0 "create_thin 0"
  1. 使用外部裝置的快照。

將一個額外引數附加到 thin 目標,指定源裝置。

dmsetup create snap --table "0 2097152 thin /dev/mapper/pool 0 /dev/image"

注意:此快照的所有子代(內部快照)都需要相同的額外源引數。

停用

所有使用池的裝置必須先停用,然後池本身才能停用。

dmsetup remove thin
dmsetup remove snap
dmsetup remove pool

參考

“thin-pool”目標

  1. 建構函式

    thin-pool <metadata dev> <data dev> <data block size (sectors)> \
              <low water mark (blocks)> [<number of feature args> [<arg>]*]
    

    可選特性引數

    skip_block_zeroing

    跳過新配置塊的歸零操作。

    ignore_discard

    停用丟棄支援。

    no_discard_passdown

    不將丟棄操作傳遞給底層資料裝置,而只刪除對映。

    read_only

    不允許對池元資料進行任何更改。此模式僅在薄池以完整的讀/寫模式建立並首次使用後可用。它不能在初始薄池建立時指定。

    error_if_no_space

    如果空間不足,則報錯 I/O,而不是排隊。

    資料塊大小必須介於 64KB (128 扇區) 和 1GB (2097152 扇區) 之間(含)。

  2. 狀態

    <transaction id> <used metadata blocks>/<total metadata blocks>
    <used data blocks>/<total data blocks> <held metadata root>
    ro|rw|out_of_data_space [no_]discard_passdown [error|queue]_if_no_space
    needs_check|- metadata_low_watermark
    
    事務 ID

    使用者空間使用的 64 位數字,用於幫助與卷管理器中的元資料同步。

    已用資料塊 / 總資料塊

    如果可用塊的數量低於池的低水位標記,將向用戶空間傳送一個 dm 事件。此事件是邊緣觸發的,並且在每次恢復後只會發生一次,因此卷管理器編寫者應該註冊此事件,然後檢查目標的狀態。

    保留的元資料根

    為使用者空間讀取訪問而“保留”的元資料根的位置(以塊為單位)。“-”表示沒有保留的根。

    啟用丟棄傳遞|停用丟棄傳遞

    丟棄操作是否實際傳遞給底層裝置。當載入表時啟用此功能時,如果底層裝置不支援,它可能會被停用。

    只讀|讀寫|資料空間不足

    如果池遇到某些型別的裝置故障,它將進入只讀元資料模式,在該模式下不允許對池元資料進行任何更改(例如分配新塊)。

    在即使只讀模式也被認為不安全的嚴重情況下,將不允許進一步的 I/O,並且狀態將只包含字串“Fail”。此時應使用使用者空間恢復工具。

    空間不足時報錯|空間不足時排隊

    如果池的資料或元資料空間耗盡,池將對目標資料裝置的 I/O 進行排隊或報錯。預設是排隊 I/O,直到新增更多空間或“no_space_timeout”過期。可以使用“no_space_timeout”dm-thin-pool 模組引數來更改此超時——它預設為 60 秒,但可以使用值 0 停用。

    需要檢查

    元資料操作失敗,導致元資料超級塊中設定了 needs_check 標誌。在薄池完全恢復執行之前,必須停用元資料裝置並進行檢查/修復。“-”表示未設定 needs_check。

    元資料低水位標記

    元資料低水位標記的值(以塊為單位)。核心在內部設定此值,但使用者空間需要知道此值以確定事件是否因超過此閾值而引起。

  3. 訊息

建立精簡裝置 <dev id>

建立一個新的精簡配置裝置。<dev id> 是呼叫者選擇的任意唯一的 24 位識別符號。

建立快照 <dev id> <origin id>

建立另一個精簡配置裝置的新快照。<dev id> 是呼叫者選擇的任意唯一的 24 位識別符號。<origin id> 是新裝置將作為其快照的精簡配置裝置的識別符號。

刪除 <dev id>

刪除一個精簡裝置。不可逆。

設定事務 ID <current id> <new id>

LVM 等使用者空間卷管理器需要一種方法來同步其外部元資料與池目標的內部元資料。“thin-pool”目標提供儲存任意 64 位事務 ID 並在目標的狀態行上返回。為避免競爭條件,當您使用此比較並交換訊息更改事務 ID 時,必須提供您認為的當前事務 ID。

保留元資料快照

保留資料對映 B 樹的副本供使用者空間使用。這允許使用者空間檢查在執行此訊息時的對映。使用池的狀態命令獲取與元資料快照關聯的根塊。

釋放元資料快照

釋放先前保留的資料對映 B 樹副本。

“thin”目標

  1. 建構函式

    thin <pool dev> <dev id> [<external origin dev>]
    
    池裝置

    薄池裝置,例如 /dev/mapper/my_pool 或 253:0

    裝置 ID

    要啟用的裝置的內部裝置識別符號。

    外部源裝置

    池外的一個可選塊裝置,將其視為只讀快照源:對精簡目標未分配區域的讀取將對映到此裝置。

池不儲存精簡裝置的任何大小資訊。如果您載入的精簡目標小於您之前使用的目標,那麼您將無法訪問超出末尾對映的塊。如果您載入的目標大於之前,則會根據需要分配額外的塊。

  1. 狀態

    <已對映扇區數> <最高對映扇區>

    如果池遇到裝置錯誤並失敗,狀態將只包含字串“Fail”。此時應使用使用者空間恢復工具。

    在 <已對映扇區數> 為 0 的情況下,沒有最高對映扇區,並且 <最高對映扇區> 的值未指定。