宋東平, 胡曉勤, 謝俊峰, 錢禹航
1(四川大學 網絡空間安全學院, 成都 610207)
2(成都云祺科技有限公司, 成都 610041)
快照是關于指定數據集在某個時間點的完全可拷貝映像, 可以作為一種備份方法使系統中的數據得到有效保護[1-3]. 常用的快照實現方法有寫時拷貝(copyon-write, COW)和寫重定向 (redirect-on-write, ROW).兩種快照方法均可實現在線快照并生成快照卷[4,5].COW[6]不改變源卷的數據分布, 在即將寫入新數據時將源卷中指定區域的數據拷貝至快照卷, 因此COW不影響源卷的讀效率, 而寫效率會造成額外的兩倍開銷. ROW[7]將新寫入的數據存儲于快照卷, 隨著寫入次數增多, 源卷的數據分布發生變化, 讀效率下降.
現有Linux 操作系統可對基于邏輯卷(logicalvolume)的塊設備在不添加額外塊設備的場景下創建快照[8,9], 但非邏輯卷塊設備缺少成熟的快照技術支撐,定時備份缺少一致性支持. 為解決這一問題, 有學者[10,11]指出非邏輯卷塊設備快照可在文件系統層或塊設備層實現. 文件系統層快照對于源數據的獲取以及快照數據的存取和解析有著較高的效率, 但需要針對特定的文件系統實現; 塊設備層快照可分為在通用塊層和物理塊層實現, 二者均可屏蔽上層文件系統的差異, 較前者更具靈活性, 但物理塊層快照不可屏蔽具體磁盤協議, 而通用塊層快照無需考慮磁盤協議, 較物理塊層快照更加靈活. 耿芳忠[12]提出了一種基于ROW 的Linux存儲卷的快照方法, 但是該方法需要添加真實塊設備作為快照卷存儲數據. 劉志勇[13]利用添加緩沖卷的方法改進了COW 效率低下的問題, 但并未解決需要額外塊設備的問題. 張權等[14]提出了一種Linux 標準分區的快照方法, 但方法仍然有上述需要添加額外塊設備存儲數據的問題. 開源軟件dattobd[15]基于塊層利用虛擬文件系統讀寫方法實現了非邏輯卷塊設備的快照并將快照數據存儲于快照源設備, 但是該軟件只能創建一個快照, 并且創建快照后快照源設備的寫效率低下, 對于實際生產的影響較大. 邏輯卷快照[16]的實現方案同樣會在快照創建后對于原始塊設備的寫效率影響比較大.
本文基于COW, 結合通用塊層的優勢, 設計實現了一種面向Linux 非邏輯卷塊設備的快照系統, 能夠在不添加額外塊設備的場景下為Linux 非邏輯卷塊設備創建快照, 并且快照對于快照源設備的寫速率影響較低.
為對不同的塊設備創建多個快照, 本文設計了一種鏈式快照存儲結構, 如圖1 所示. 建立一個head 節點作為全局快照鏈的頭節點, 僅用于快照鏈尋址. 建立device_head 鏈作為主塊設備鏈(例如: sdx1 的主設備為sdx), 通過訪問該鏈上的節點實現對具體快照頭結點的查找. 建立snap_head 鏈作為快照鏈頭結點鏈, 通過訪問該鏈上的節點實現對快照源設備(具體到分區,例如: sdx1)的確定和快照鏈的確定. 建立snap 鏈作為快照鏈, 通過訪問該鏈上的節點實現相同塊設備的不同快照的確定. 該結構實現了對于不同塊設備、同一塊設備內部不同分區以及不同快照的記錄. 快照節點信息將根據該結構進行保存.

圖1 快照存儲結構圖
為記錄塊設備的拷貝映射信息, 本文設計了一種廣義Bitmap 結構進行存儲, 如圖2 所示. 一條Bitmap記錄占18 字節, 從左起第1 字節作為標志位, 用于標記當前拷貝塊(一次COW 拷貝多少數據, 自定義大小,不同于操作系統的數據塊)有無拷貝記錄, 第2-9 字節用于記錄該拷貝塊在快照源設備中的邏輯扇區號即拷貝源地址, 第10 字節為保留位, 第11-18 字節用于記錄該拷貝塊拷貝后的邏輯扇區號即拷貝目的地址. 通過該Bitmap 存儲結構可以記錄原始拷貝塊的拷貝標記和拷貝塊的拷貝前后地址映射.

圖2 Bitmap 存儲結構圖
快照系統設計為前后端模式, 分別對應應用層程序和內核層程序, 內核層程序主要位于通用塊層. 前端程序主要處理用戶命令以及文件操作, 后端程序主要執行快照底層邏輯, 系統模塊組成及其關系如圖3 所示. 快照處理模塊由命令接口和快照管理兩部分構成.命令接口屬于前端程序, 用于接收用戶的快照創建或刪除命令, 然后依照該命令對快照文件進行相應的操作(快照文件由位圖文件.bit 和數據文件.data 組成), 完成后將該命令發送到快照管理. 快照管理屬于后端程序, 用于接收并解析命令接口發送的命令, 然后依照該命令進行快照設備及過濾器的創建或刪除, 快照設備為內存塊設備, 其數據存儲于快照源設備上. 過濾器、COW 模塊以及快照設備的讀模塊屬于后端程序. 過濾器在創建后對快照源設備進行通用塊層的I/O 請求(block input outpu, bio)截獲, 并將截獲到的寫bio 轉發到COW 模塊, 將讀bio 轉發回快照源設備. COW 模塊根據接收到的bio 進行數據拷貝操作, 然后將該bio 轉發回快照源設備以完成COW. 快照設備的讀模塊將發送到快照設備的讀bio 重定向到快照源設備以完成快照設備的讀請求處理.

圖3 快照系統架構圖
快照創建與刪除工作主要由快照處理模塊完成.模塊包含命令接口和快照管理兩部分. 命令接口用于對用戶傳入的命令進行解析, 快照管理用于對命令接口發送的命令進行通用塊層的處理, 快照創建與刪除流程如圖4 所示.
創建流程如圖4(a)所示. 命令接口首先查詢設備是否存在, 不存在則結束創建, 存在則查詢快照源設備的設備大小、設備掛載點以及設備的主次設備號等有關該設備的基本信息, 隨后在設備掛載點下創建一組空洞文件作為快照文件并獲取該組文件在塊設備上的邏輯扇區分布(其中.bit 文件用于存儲Bitmap 數據,.data 文件用于存儲COW 過程中拷貝的數據), 目的是為了在通用塊層進行數據拷貝時從通用塊層存取Bitmap 記錄以及定位數據的存儲位置. 然后注冊信號處理回調, 回調用于處理快照管理發送的創建信號以及刪除信號. 隨后發送創建命令到快照管理. 快照管理在接收到創建快照命令后依次創建一個快照設備和一個快照源設備bio 過濾器(一個快照源設備只對應一個過濾器, 如果存在則不創建), 隨后將其添加到全局快照鏈中, 然后將塊設備大小按照拷貝塊劃分, 將各個拷貝塊的起始扇區號作為原始數據所在扇區號按照Bitmap 存儲結構存儲于.bit 文件所對應的邏輯扇區上,將數據拷貝后所在扇區號置0, 隨后發送創建結束信號到命令接口觸發該信號的處理回調, 創建快照過程結束.刪除流程如圖4(b)所示. 命令接口首先查詢該快照是否存在, 不存在則結束刪除, 存在則發送刪除命令到快照管理. 快照管理接收到刪除命令后將過濾器和快照設備刪除(如果該快照源設備還存在快照, 則不刪除過濾器), 隨后將其從全局快照鏈中移除, 然后發送刪除結束信號到命令接口觸發該信號的處理回調, 刪除快照過程結束.

圖4 快照創建與刪除流程圖
快照寫工作主要由過濾器和COW 模塊完成, 其中過濾器用于快照源設備bio 的截獲, 然后對其按讀寫類型進行分類, COW 模塊主要進行數據拷貝操作. 流程如圖5 所示.
過濾器的創建方法為首先獲取快照源設備的設備對象, 根據設備對象獲取通用塊層入口函數指針, 使用自定義的函數對其進行替換, 至此過濾器創建成功. 在過濾流程中, 對于讀bio, 處理方式為轉發到快照源設備; 對于寫bio, 處理方式為轉發到COW 模塊. 過濾流程如圖5(a)所示.
COW 模塊在接收到bio 后從Bitmap 中查詢該bio 所指向的數據塊所在的拷貝塊有無拷貝記錄. 對于有拷貝記錄的拷貝塊, 處理方法為轉發該bio 到快照源設備; 對于沒有拷貝記錄的拷貝塊, 處理方法為先進行邏輯上的拷貝再進行物理上的拷貝. 邏輯上的拷貝首先根據截獲到的bio 和已拷貝的數據塊大小計算出拷貝塊的拷貝源地址和拷貝目的地址, 然后對Bitmap 進行更新. 物理上的拷貝首先對該拷貝塊進行通用塊層的數據讀取, 然后將數據在通用塊層寫入拷貝目的地址中. 通用塊層的數據讀寫方法即為構造bio 進行數據讀寫. 拷貝完成后再將該bio 轉發回快照源設備. COW流程如圖5(b) 所示. 其中, 拷貝源地址可通過式(1)計算得出:


圖5 快照寫流程圖
快照讀工作主要由快照設備中的讀模塊完成, 讀流程如圖6. 模塊在接收到讀bio 后從中獲取該bio 指向的數據塊在塊設備中的偏移, 依據偏移查詢Bitmap 以獲得該數據塊所在拷貝塊的拷貝記錄. 對于沒有拷貝記錄的拷貝塊, 處理方法為重定向該bio 到快照源設備. 對于有拷貝記錄的拷貝塊, 處理方法為先從Bitmap 中獲取該拷貝塊的拷貝目的地址, 然后將bio 重定向到該拷貝目的地址, 因此讀模塊獲取到的數據即快照之前的數據.

圖6 快照讀流程圖
由于COW 對快照源設備的讀速率沒有影響, 并且已經進行了COW 的數據塊在覆蓋寫過程中不會產生性能損耗, 因此本文實驗僅依據快照源設備的新增寫速率損耗便可衡量系統性能, 損耗量與系統性能成反比. 其中新增寫為每創建一個快照就向快照源設備寫一個指定大小的全新文件. 本文設計了3 個實驗, 分別為快照數據的正確性驗證實驗、拷貝塊大小對系統性能的影響測試實驗以及快照個數對比實驗. 所有實驗均在虛擬化環境中進行, 采用直接I/O 的方式將數據寫入塊設備上的文件, 單次I/O 塊文件大小為4 KB,具體實驗環境如表1 所示. 其中塊設備1 名為/dev/sdb1,為非邏輯卷塊設備, 掛載點為/sdb1. 塊設備2 名為/dev/sdc1, 為邏輯卷塊設備, 邏輯卷為/dev/vg_1/lv_test.

表1 實驗環境配置表
本實驗在對塊設備/dev/sdb1 創建快照前在其掛載點/sdb1 目錄下創建一個1 GB 的文件test_1G, 計算該文件的MD5. 在對/dev/sdb1 創建快照后修改test_1G文件, 隨后將生成的快照設備/dev/sdb1-snapshot1 掛載于/snap 目錄下, 計算/snap 目錄下的 test_1G 文件的MD5. MD5 記錄如表2 所示.

表2 文件MD5 表
表2 表明, 對/dev/sdb1 創建快照后快照設備/dev/sdb1-snapshot1 中的test_1G 文件的MD5 值與快照前快照源設備中的test_1G 文件的MD5 值一致, 這說明快照設備中的文件內容與快照源設備快照前的文件內容一致, 進而證明了本系統創建的非邏輯卷塊設備快照能夠確保數據的正確性.
本實驗選用了1 MB、2 MB、4 MB 和8 MB 大小的拷貝塊進行快照源設備的寫速率比較進而衡量系統性能, 針對每一種拷貝塊大小, 均在拷貝后向快照源設備寫入一個1 GB 的全新文件, 測試其平均寫速率. 平均寫速率與拷貝塊大小的關系如圖7 所示.
圖7 表明當拷貝塊為4 MB 大小時快照源設備寫速率最高, 同等條件下其速率損耗最小, 而隨著拷貝塊增大或減小都會使速率損耗增大. 這是因為拷貝塊粒度過細會導致COW 操作過于頻繁, 從而引起真實I/O 操作過多耗時, 拷貝塊粒度過粗會導致單次COW 過程中讀寫數據量過大而引起耗時, 二者都會成為影響快照源設備寫速率的因素. 因此本系統4 MB 拷貝塊大小下對于快照源設備新增寫速率影響最小, 性能表現最佳.

圖7 拷貝塊大小對寫速率的影響
本實驗分為單快照子實驗和多快照子實驗. 在單快照子實驗中將本系統與其他同類系統均創建1 個快照進行新增寫速率損耗對比. 在多快照實驗中利用本系統創建多個快照, 然后進行速率損耗自我對比. 實驗均采用4 MB 作為本系統的拷貝塊大小.
3.3.1 單快照
本實驗對塊設備/dev/sdb1 分別利用本系統和開源軟件dattobd 創建單個快照, 然后向其中新增寫1 GB文件, 對邏輯卷/dev/vg_1/lv_test 利用邏輯卷的快照方法創建單個快照, 然后同樣向其中新增寫1 GB 文件,記錄三者所創建快照存在的情況下快照源設備的新增寫速率并計算出速率損耗, 實驗結果如表3 所示.

表3 不同系統下快照對新增寫速率的影響
表3 表明, 在只創建一個快照的情況下, 本系統對于快照源設備的新增寫速率損耗低于7%, 開源軟件dattobd 的速率損耗高于35%, 邏輯卷的速率損耗高于55%. 這是因為本系統在通用塊層進行COW, 而dattobd和邏輯卷分別在虛擬文件系統層和邏輯卷管理層進行COW, 二者在Linux 內核中的層次均高于通用塊層, 因此通用塊層I/O 落盤速率遠高于上層, 因此本系統對于快照源設備的新增寫速率影響較已經存在的兩種系統有明顯下降, 本系統性能優于已有的兩種快照方案.
3.3.2 多快照
本實驗對塊設備/dev/sdb1 創建9 個快照并進行新增寫, 新增寫文件大小為1 GB, 記錄不同快照個數下快照源設備的新增寫速率及其損耗百分比, 實驗結果如表4 所示.

表4 新增寫速率及損耗
本文設計實現了一種面向Linux 非邏輯卷塊設備的快照系統. 系統依賴于COW 技術, 結合通用塊層的優勢, 實現了在不添加額外塊設備的場景下對Linux非邏輯卷塊設備創建快照, 并且較已有的快照方案有明顯的新增寫速率損耗降低, 滿足了Linux 非邏輯卷塊設備定時備份過程中對于快照的需求. 系統性能在拷貝塊為4 MB 大小, 快照個數為1 時最優, 快照個數少于5 時表現良好. 但本系統存在當快照個數過多時性能變差, 對于快照源設備的新增寫性能損耗偏大問題, 后續可對系統結構和數據存儲方案進行優化.