宋東平, 胡曉勤, 謝俊峰, 錢禹航
1(四川大學(xué) 網(wǎng)絡(luò)空間安全學(xué)院, 成都 610207)
2(成都云祺科技有限公司, 成都 610041)
快照是關(guān)于指定數(shù)據(jù)集在某個(gè)時(shí)間點(diǎn)的完全可拷貝映像, 可以作為一種備份方法使系統(tǒng)中的數(shù)據(jù)得到有效保護(hù)[1-3]. 常用的快照實(shí)現(xiàn)方法有寫(xiě)時(shí)拷貝(copyon-write, COW)和寫(xiě)重定向 (redirect-on-write, ROW).兩種快照方法均可實(shí)現(xiàn)在線快照并生成快照卷[4,5].COW[6]不改變?cè)淳淼臄?shù)據(jù)分布, 在即將寫(xiě)入新數(shù)據(jù)時(shí)將源卷中指定區(qū)域的數(shù)據(jù)拷貝至快照卷, 因此COW不影響源卷的讀效率, 而寫(xiě)效率會(huì)造成額外的兩倍開(kāi)銷. ROW[7]將新寫(xiě)入的數(shù)據(jù)存儲(chǔ)于快照卷, 隨著寫(xiě)入次數(shù)增多, 源卷的數(shù)據(jù)分布發(fā)生變化, 讀效率下降.
現(xiàn)有Linux 操作系統(tǒng)可對(duì)基于邏輯卷(logicalvolume)的塊設(shè)備在不添加額外塊設(shè)備的場(chǎng)景下創(chuàng)建快照[8,9], 但非邏輯卷塊設(shè)備缺少成熟的快照技術(shù)支撐,定時(shí)備份缺少一致性支持. 為解決這一問(wèn)題, 有學(xué)者[10,11]指出非邏輯卷塊設(shè)備快照可在文件系統(tǒng)層或塊設(shè)備層實(shí)現(xiàn). 文件系統(tǒng)層快照對(duì)于源數(shù)據(jù)的獲取以及快照數(shù)據(jù)的存取和解析有著較高的效率, 但需要針對(duì)特定的文件系統(tǒng)實(shí)現(xiàn); 塊設(shè)備層快照可分為在通用塊層和物理塊層實(shí)現(xiàn), 二者均可屏蔽上層文件系統(tǒng)的差異, 較前者更具靈活性, 但物理塊層快照不可屏蔽具體磁盤協(xié)議, 而通用塊層快照無(wú)需考慮磁盤協(xié)議, 較物理塊層快照更加靈活. 耿芳忠[12]提出了一種基于ROW 的Linux存儲(chǔ)卷的快照方法, 但是該方法需要添加真實(shí)塊設(shè)備作為快照卷存儲(chǔ)數(shù)據(jù). 劉志勇[13]利用添加緩沖卷的方法改進(jìn)了COW 效率低下的問(wèn)題, 但并未解決需要額外塊設(shè)備的問(wèn)題. 張權(quán)等[14]提出了一種Linux 標(biāo)準(zhǔn)分區(qū)的快照方法, 但方法仍然有上述需要添加額外塊設(shè)備存儲(chǔ)數(shù)據(jù)的問(wèn)題. 開(kāi)源軟件dattobd[15]基于塊層利用虛擬文件系統(tǒng)讀寫(xiě)方法實(shí)現(xiàn)了非邏輯卷塊設(shè)備的快照并將快照數(shù)據(jù)存儲(chǔ)于快照源設(shè)備, 但是該軟件只能創(chuàng)建一個(gè)快照, 并且創(chuàng)建快照后快照源設(shè)備的寫(xiě)效率低下, 對(duì)于實(shí)際生產(chǎn)的影響較大. 邏輯卷快照[16]的實(shí)現(xiàn)方案同樣會(huì)在快照創(chuàng)建后對(duì)于原始?jí)K設(shè)備的寫(xiě)效率影響比較大.
本文基于COW, 結(jié)合通用塊層的優(yōu)勢(shì), 設(shè)計(jì)實(shí)現(xiàn)了一種面向Linux 非邏輯卷塊設(shè)備的快照系統(tǒng), 能夠在不添加額外塊設(shè)備的場(chǎng)景下為L(zhǎng)inux 非邏輯卷塊設(shè)備創(chuàng)建快照, 并且快照對(duì)于快照源設(shè)備的寫(xiě)速率影響較低.
為對(duì)不同的塊設(shè)備創(chuàng)建多個(gè)快照, 本文設(shè)計(jì)了一種鏈?zhǔn)娇煺沾鎯?chǔ)結(jié)構(gòu), 如圖1 所示. 建立一個(gè)head 節(jié)點(diǎn)作為全局快照鏈的頭節(jié)點(diǎn), 僅用于快照鏈尋址. 建立device_head 鏈作為主塊設(shè)備鏈(例如: sdx1 的主設(shè)備為sdx), 通過(guò)訪問(wèn)該鏈上的節(jié)點(diǎn)實(shí)現(xiàn)對(duì)具體快照頭結(jié)點(diǎn)的查找. 建立snap_head 鏈作為快照鏈頭結(jié)點(diǎn)鏈, 通過(guò)訪問(wèn)該鏈上的節(jié)點(diǎn)實(shí)現(xiàn)對(duì)快照源設(shè)備(具體到分區(qū),例如: sdx1)的確定和快照鏈的確定. 建立snap 鏈作為快照鏈, 通過(guò)訪問(wèn)該鏈上的節(jié)點(diǎn)實(shí)現(xiàn)相同塊設(shè)備的不同快照的確定. 該結(jié)構(gòu)實(shí)現(xiàn)了對(duì)于不同塊設(shè)備、同一塊設(shè)備內(nèi)部不同分區(qū)以及不同快照的記錄. 快照節(jié)點(diǎn)信息將根據(jù)該結(jié)構(gòu)進(jìn)行保存.
圖1 快照存儲(chǔ)結(jié)構(gòu)圖
為記錄塊設(shè)備的拷貝映射信息, 本文設(shè)計(jì)了一種廣義Bitmap 結(jié)構(gòu)進(jìn)行存儲(chǔ), 如圖2 所示. 一條Bitmap記錄占18 字節(jié), 從左起第1 字節(jié)作為標(biāo)志位, 用于標(biāo)記當(dāng)前拷貝塊(一次COW 拷貝多少數(shù)據(jù), 自定義大小,不同于操作系統(tǒng)的數(shù)據(jù)塊)有無(wú)拷貝記錄, 第2-9 字節(jié)用于記錄該拷貝塊在快照源設(shè)備中的邏輯扇區(qū)號(hào)即拷貝源地址, 第10 字節(jié)為保留位, 第11-18 字節(jié)用于記錄該拷貝塊拷貝后的邏輯扇區(qū)號(hào)即拷貝目的地址. 通過(guò)該Bitmap 存儲(chǔ)結(jié)構(gòu)可以記錄原始拷貝塊的拷貝標(biāo)記和拷貝塊的拷貝前后地址映射.
圖2 Bitmap 存儲(chǔ)結(jié)構(gòu)圖
快照系統(tǒng)設(shè)計(jì)為前后端模式, 分別對(duì)應(yīng)應(yīng)用層程序和內(nèi)核層程序, 內(nèi)核層程序主要位于通用塊層. 前端程序主要處理用戶命令以及文件操作, 后端程序主要執(zhí)行快照底層邏輯, 系統(tǒng)模塊組成及其關(guān)系如圖3 所示. 快照處理模塊由命令接口和快照管理兩部分構(gòu)成.命令接口屬于前端程序, 用于接收用戶的快照創(chuàng)建或刪除命令, 然后依照該命令對(duì)快照文件進(jìn)行相應(yīng)的操作(快照文件由位圖文件.bit 和數(shù)據(jù)文件.data 組成), 完成后將該命令發(fā)送到快照管理. 快照管理屬于后端程序, 用于接收并解析命令接口發(fā)送的命令, 然后依照該命令進(jìn)行快照設(shè)備及過(guò)濾器的創(chuàng)建或刪除, 快照設(shè)備為內(nèi)存塊設(shè)備, 其數(shù)據(jù)存儲(chǔ)于快照源設(shè)備上. 過(guò)濾器、COW 模塊以及快照設(shè)備的讀模塊屬于后端程序. 過(guò)濾器在創(chuàng)建后對(duì)快照源設(shè)備進(jìn)行通用塊層的I/O 請(qǐng)求(block input outpu, bio)截獲, 并將截獲到的寫(xiě)bio 轉(zhuǎn)發(fā)到COW 模塊, 將讀bio 轉(zhuǎn)發(fā)回快照源設(shè)備. COW 模塊根據(jù)接收到的bio 進(jìn)行數(shù)據(jù)拷貝操作, 然后將該bio 轉(zhuǎn)發(fā)回快照源設(shè)備以完成COW. 快照設(shè)備的讀模塊將發(fā)送到快照設(shè)備的讀bio 重定向到快照源設(shè)備以完成快照設(shè)備的讀請(qǐng)求處理.
圖3 快照系統(tǒng)架構(gòu)圖
快照創(chuàng)建與刪除工作主要由快照處理模塊完成.模塊包含命令接口和快照管理兩部分. 命令接口用于對(duì)用戶傳入的命令進(jìn)行解析, 快照管理用于對(duì)命令接口發(fā)送的命令進(jìn)行通用塊層的處理, 快照創(chuàng)建與刪除流程如圖4 所示.
創(chuàng)建流程如圖4(a)所示. 命令接口首先查詢?cè)O(shè)備是否存在, 不存在則結(jié)束創(chuàng)建, 存在則查詢快照源設(shè)備的設(shè)備大小、設(shè)備掛載點(diǎn)以及設(shè)備的主次設(shè)備號(hào)等有關(guān)該設(shè)備的基本信息, 隨后在設(shè)備掛載點(diǎn)下創(chuàng)建一組空洞文件作為快照文件并獲取該組文件在塊設(shè)備上的邏輯扇區(qū)分布(其中.bit 文件用于存儲(chǔ)Bitmap 數(shù)據(jù),.data 文件用于存儲(chǔ)COW 過(guò)程中拷貝的數(shù)據(jù)), 目的是為了在通用塊層進(jìn)行數(shù)據(jù)拷貝時(shí)從通用塊層存取Bitmap 記錄以及定位數(shù)據(jù)的存儲(chǔ)位置. 然后注冊(cè)信號(hào)處理回調(diào), 回調(diào)用于處理快照管理發(fā)送的創(chuàng)建信號(hào)以及刪除信號(hào). 隨后發(fā)送創(chuàng)建命令到快照管理. 快照管理在接收到創(chuàng)建快照命令后依次創(chuàng)建一個(gè)快照設(shè)備和一個(gè)快照源設(shè)備bio 過(guò)濾器(一個(gè)快照源設(shè)備只對(duì)應(yīng)一個(gè)過(guò)濾器, 如果存在則不創(chuàng)建), 隨后將其添加到全局快照鏈中, 然后將塊設(shè)備大小按照拷貝塊劃分, 將各個(gè)拷貝塊的起始扇區(qū)號(hào)作為原始數(shù)據(jù)所在扇區(qū)號(hào)按照Bitmap 存儲(chǔ)結(jié)構(gòu)存儲(chǔ)于.bit 文件所對(duì)應(yīng)的邏輯扇區(qū)上,將數(shù)據(jù)拷貝后所在扇區(qū)號(hào)置0, 隨后發(fā)送創(chuàng)建結(jié)束信號(hào)到命令接口觸發(fā)該信號(hào)的處理回調(diào), 創(chuàng)建快照過(guò)程結(jié)束.刪除流程如圖4(b)所示. 命令接口首先查詢?cè)摽煺帐欠翊嬖? 不存在則結(jié)束刪除, 存在則發(fā)送刪除命令到快照管理. 快照管理接收到刪除命令后將過(guò)濾器和快照設(shè)備刪除(如果該快照源設(shè)備還存在快照, 則不刪除過(guò)濾器), 隨后將其從全局快照鏈中移除, 然后發(fā)送刪除結(jié)束信號(hào)到命令接口觸發(fā)該信號(hào)的處理回調(diào), 刪除快照過(guò)程結(jié)束.
圖4 快照創(chuàng)建與刪除流程圖
快照寫(xiě)工作主要由過(guò)濾器和COW 模塊完成, 其中過(guò)濾器用于快照源設(shè)備bio 的截獲, 然后對(duì)其按讀寫(xiě)類型進(jìn)行分類, COW 模塊主要進(jìn)行數(shù)據(jù)拷貝操作. 流程如圖5 所示.
過(guò)濾器的創(chuàng)建方法為首先獲取快照源設(shè)備的設(shè)備對(duì)象, 根據(jù)設(shè)備對(duì)象獲取通用塊層入口函數(shù)指針, 使用自定義的函數(shù)對(duì)其進(jìn)行替換, 至此過(guò)濾器創(chuàng)建成功. 在過(guò)濾流程中, 對(duì)于讀bio, 處理方式為轉(zhuǎn)發(fā)到快照源設(shè)備; 對(duì)于寫(xiě)bio, 處理方式為轉(zhuǎn)發(fā)到COW 模塊. 過(guò)濾流程如圖5(a)所示.
COW 模塊在接收到bio 后從Bitmap 中查詢?cè)揵io 所指向的數(shù)據(jù)塊所在的拷貝塊有無(wú)拷貝記錄. 對(duì)于有拷貝記錄的拷貝塊, 處理方法為轉(zhuǎn)發(fā)該bio 到快照源設(shè)備; 對(duì)于沒(méi)有拷貝記錄的拷貝塊, 處理方法為先進(jìn)行邏輯上的拷貝再進(jìn)行物理上的拷貝. 邏輯上的拷貝首先根據(jù)截獲到的bio 和已拷貝的數(shù)據(jù)塊大小計(jì)算出拷貝塊的拷貝源地址和拷貝目的地址, 然后對(duì)Bitmap 進(jìn)行更新. 物理上的拷貝首先對(duì)該拷貝塊進(jìn)行通用塊層的數(shù)據(jù)讀取, 然后將數(shù)據(jù)在通用塊層寫(xiě)入拷貝目的地址中. 通用塊層的數(shù)據(jù)讀寫(xiě)方法即為構(gòu)造bio 進(jìn)行數(shù)據(jù)讀寫(xiě). 拷貝完成后再將該bio 轉(zhuǎn)發(fā)回快照源設(shè)備. COW流程如圖5(b) 所示. 其中, 拷貝源地址可通過(guò)式(1)計(jì)算得出:
圖5 快照寫(xiě)流程圖
快照讀工作主要由快照設(shè)備中的讀模塊完成, 讀流程如圖6. 模塊在接收到讀bio 后從中獲取該bio 指向的數(shù)據(jù)塊在塊設(shè)備中的偏移, 依據(jù)偏移查詢Bitmap 以獲得該數(shù)據(jù)塊所在拷貝塊的拷貝記錄. 對(duì)于沒(méi)有拷貝記錄的拷貝塊, 處理方法為重定向該bio 到快照源設(shè)備. 對(duì)于有拷貝記錄的拷貝塊, 處理方法為先從Bitmap 中獲取該拷貝塊的拷貝目的地址, 然后將bio 重定向到該拷貝目的地址, 因此讀模塊獲取到的數(shù)據(jù)即快照之前的數(shù)據(jù).
圖6 快照讀流程圖
由于COW 對(duì)快照源設(shè)備的讀速率沒(méi)有影響, 并且已經(jīng)進(jìn)行了COW 的數(shù)據(jù)塊在覆蓋寫(xiě)過(guò)程中不會(huì)產(chǎn)生性能損耗, 因此本文實(shí)驗(yàn)僅依據(jù)快照源設(shè)備的新增寫(xiě)速率損耗便可衡量系統(tǒng)性能, 損耗量與系統(tǒng)性能成反比. 其中新增寫(xiě)為每創(chuàng)建一個(gè)快照就向快照源設(shè)備寫(xiě)一個(gè)指定大小的全新文件. 本文設(shè)計(jì)了3 個(gè)實(shí)驗(yàn), 分別為快照數(shù)據(jù)的正確性驗(yàn)證實(shí)驗(yàn)、拷貝塊大小對(duì)系統(tǒng)性能的影響測(cè)試實(shí)驗(yàn)以及快照個(gè)數(shù)對(duì)比實(shí)驗(yàn). 所有實(shí)驗(yàn)均在虛擬化環(huán)境中進(jìn)行, 采用直接I/O 的方式將數(shù)據(jù)寫(xiě)入塊設(shè)備上的文件, 單次I/O 塊文件大小為4 KB,具體實(shí)驗(yàn)環(huán)境如表1 所示. 其中塊設(shè)備1 名為/dev/sdb1,為非邏輯卷塊設(shè)備, 掛載點(diǎn)為/sdb1. 塊設(shè)備2 名為/dev/sdc1, 為邏輯卷塊設(shè)備, 邏輯卷為/dev/vg_1/lv_test.
表1 實(shí)驗(yàn)環(huán)境配置表
本實(shí)驗(yàn)在對(duì)塊設(shè)備/dev/sdb1 創(chuàng)建快照前在其掛載點(diǎn)/sdb1 目錄下創(chuàng)建一個(gè)1 GB 的文件test_1G, 計(jì)算該文件的MD5. 在對(duì)/dev/sdb1 創(chuàng)建快照后修改test_1G文件, 隨后將生成的快照設(shè)備/dev/sdb1-snapshot1 掛載于/snap 目錄下, 計(jì)算/snap 目錄下的 test_1G 文件的MD5. MD5 記錄如表2 所示.
表2 文件MD5 表
表2 表明, 對(duì)/dev/sdb1 創(chuàng)建快照后快照設(shè)備/dev/sdb1-snapshot1 中的test_1G 文件的MD5 值與快照前快照源設(shè)備中的test_1G 文件的MD5 值一致, 這說(shuō)明快照設(shè)備中的文件內(nèi)容與快照源設(shè)備快照前的文件內(nèi)容一致, 進(jìn)而證明了本系統(tǒng)創(chuàng)建的非邏輯卷塊設(shè)備快照能夠確保數(shù)據(jù)的正確性.
本實(shí)驗(yàn)選用了1 MB、2 MB、4 MB 和8 MB 大小的拷貝塊進(jìn)行快照源設(shè)備的寫(xiě)速率比較進(jìn)而衡量系統(tǒng)性能, 針對(duì)每一種拷貝塊大小, 均在拷貝后向快照源設(shè)備寫(xiě)入一個(gè)1 GB 的全新文件, 測(cè)試其平均寫(xiě)速率. 平均寫(xiě)速率與拷貝塊大小的關(guān)系如圖7 所示.
圖7 表明當(dāng)拷貝塊為4 MB 大小時(shí)快照源設(shè)備寫(xiě)速率最高, 同等條件下其速率損耗最小, 而隨著拷貝塊增大或減小都會(huì)使速率損耗增大. 這是因?yàn)榭截悏K粒度過(guò)細(xì)會(huì)導(dǎo)致COW 操作過(guò)于頻繁, 從而引起真實(shí)I/O 操作過(guò)多耗時(shí), 拷貝塊粒度過(guò)粗會(huì)導(dǎo)致單次COW 過(guò)程中讀寫(xiě)數(shù)據(jù)量過(guò)大而引起耗時(shí), 二者都會(huì)成為影響快照源設(shè)備寫(xiě)速率的因素. 因此本系統(tǒng)4 MB 拷貝塊大小下對(duì)于快照源設(shè)備新增寫(xiě)速率影響最小, 性能表現(xiàn)最佳.
圖7 拷貝塊大小對(duì)寫(xiě)速率的影響
本實(shí)驗(yàn)分為單快照子實(shí)驗(yàn)和多快照子實(shí)驗(yàn). 在單快照子實(shí)驗(yàn)中將本系統(tǒng)與其他同類系統(tǒng)均創(chuàng)建1 個(gè)快照進(jìn)行新增寫(xiě)速率損耗對(duì)比. 在多快照實(shí)驗(yàn)中利用本系統(tǒng)創(chuàng)建多個(gè)快照, 然后進(jìn)行速率損耗自我對(duì)比. 實(shí)驗(yàn)均采用4 MB 作為本系統(tǒng)的拷貝塊大小.
3.3.1 單快照
本實(shí)驗(yàn)對(duì)塊設(shè)備/dev/sdb1 分別利用本系統(tǒng)和開(kāi)源軟件dattobd 創(chuàng)建單個(gè)快照, 然后向其中新增寫(xiě)1 GB文件, 對(duì)邏輯卷/dev/vg_1/lv_test 利用邏輯卷的快照方法創(chuàng)建單個(gè)快照, 然后同樣向其中新增寫(xiě)1 GB 文件,記錄三者所創(chuàng)建快照存在的情況下快照源設(shè)備的新增寫(xiě)速率并計(jì)算出速率損耗, 實(shí)驗(yàn)結(jié)果如表3 所示.
表3 不同系統(tǒng)下快照對(duì)新增寫(xiě)速率的影響
表3 表明, 在只創(chuàng)建一個(gè)快照的情況下, 本系統(tǒng)對(duì)于快照源設(shè)備的新增寫(xiě)速率損耗低于7%, 開(kāi)源軟件dattobd 的速率損耗高于35%, 邏輯卷的速率損耗高于55%. 這是因?yàn)楸鞠到y(tǒng)在通用塊層進(jìn)行COW, 而dattobd和邏輯卷分別在虛擬文件系統(tǒng)層和邏輯卷管理層進(jìn)行COW, 二者在Linux 內(nèi)核中的層次均高于通用塊層, 因此通用塊層I/O 落盤速率遠(yuǎn)高于上層, 因此本系統(tǒng)對(duì)于快照源設(shè)備的新增寫(xiě)速率影響較已經(jīng)存在的兩種系統(tǒng)有明顯下降, 本系統(tǒng)性能優(yōu)于已有的兩種快照方案.
3.3.2 多快照
本實(shí)驗(yàn)對(duì)塊設(shè)備/dev/sdb1 創(chuàng)建9 個(gè)快照并進(jìn)行新增寫(xiě), 新增寫(xiě)文件大小為1 GB, 記錄不同快照個(gè)數(shù)下快照源設(shè)備的新增寫(xiě)速率及其損耗百分比, 實(shí)驗(yàn)結(jié)果如表4 所示.
表4 新增寫(xiě)速率及損耗
本文設(shè)計(jì)實(shí)現(xiàn)了一種面向Linux 非邏輯卷塊設(shè)備的快照系統(tǒng). 系統(tǒng)依賴于COW 技術(shù), 結(jié)合通用塊層的優(yōu)勢(shì), 實(shí)現(xiàn)了在不添加額外塊設(shè)備的場(chǎng)景下對(duì)Linux非邏輯卷塊設(shè)備創(chuàng)建快照, 并且較已有的快照方案有明顯的新增寫(xiě)速率損耗降低, 滿足了Linux 非邏輯卷塊設(shè)備定時(shí)備份過(guò)程中對(duì)于快照的需求. 系統(tǒng)性能在拷貝塊為4 MB 大小, 快照個(gè)數(shù)為1 時(shí)最優(yōu), 快照個(gè)數(shù)少于5 時(shí)表現(xiàn)良好. 但本系統(tǒng)存在當(dāng)快照個(gè)數(shù)過(guò)多時(shí)性能變差, 對(duì)于快照源設(shè)備的新增寫(xiě)性能損耗偏大問(wèn)題, 后續(xù)可對(duì)系統(tǒng)結(jié)構(gòu)和數(shù)據(jù)存儲(chǔ)方案進(jìn)行優(yōu)化.