陳 博,何連躍,嚴巍巍,徐照淼,徐 俊
(1.國防科技大學計算機學院,長沙410073; 2.北京網云飛信息技術有限公司,北京100067)
(* 通信作者電子郵箱bochen.aries@gmail.com)
近年來,Hadoop分布式文件系統(Hadoop Distributed File System,HDFS)[1]以其高可靠性、高容錯性、高可擴展性等優點得到工業界和學術界的青睞。HDFS設計初衷是實現大規模集群以支持大數據集的存儲,并為運行在其之上的大數據應用提供高并發訪問支持,因此,HDFS存儲的文件主要是GB級或TB級以上的大文件。此外,為了實現集群數據的流式訪問,HDFS放寬了一部分可移植操作系統接口(Portable Operating System Interface of UNIX,POSIX)約束[2],包括不支持文件的隨機寫操作以及刪減了Linux下文件的可執行屬性概念等。
隨著云存儲應用的普及,越來越多的應用產生對海量小文件的存儲需求。基于這類應用存儲需求,學術界圍繞小文件聚合技術提出不少適用于海量小文件存儲的方案[3-7],然而這些方案大多是基于特定的目錄結構或是針對特殊文件格式進行的優化,在一定程度上不具備通用性。為此,國防科技大學實現了基于大空間聚合技術的海量小文件系統(Mass Small Distributed File System,SMDFS)[8],支持任意目錄結構和任意格式文件的存儲。
SMDFS基于HDFS研發,既繼承了HDFS高吞吐量訪問、高容錯性等優點,同時也遺留了不兼容POSIX約束的問題,因此SMDFS在校園、企業和政府等群體的在線辦公應用場景中,存在不支持文件的任意編輯等問題。除此之外,SMDFS提供的HDFS標準接口符合POSIX接口語義,不能直接兼容現有的B/S、C/S架構應用。
本文針對分布式文件系統SMDFS不兼容POSIX約束的問題,提出并實現了基于本地數據緩存的POSIX兼容技術以及基于數據暫存區的元數據高效管理技術。
SMDFS POSIX兼容最直接的實現方式是放棄文件的流式讀寫,修改底層存儲文件的訪問方式,但是這意味著系統并發性能的極大損耗。其次,對SMDFS來說,文件訪問方式的改變必然導致文件訪問接口與標準HDFS API產生差異,最終致使系統不支持Spark、Yarn、HBase等能部署在HDFS上的大數據應用。基于此,本文提出基于本地數據緩存的POSIX兼容技術。
POSIX兼容技術的核心是基于Linux本地文件系統的POSIX兼容特性來實現文件流的重定向。實現文件流的重定向,需要在用戶層與存儲應用層之間的POSIX兼容層內設置數據暫存區,用于維護操作的目標文件的鏡像。SMDFS POSIX兼容層根據文件讀寫模式對文件流進行重定向處理。
用戶進行文件只寫操作時,保持HDFS的寫穿透模式以提高文件上傳效率。由于SMDFS對小文件采用聚合存儲,聚合文件中的單個小文件不能修改,如圖1所示,在處理讀寫模式文件流重定向之前,若SMDFS存儲層已存在目標文件,需要先將目標文件下傳至數據暫存區作為鏡像,等待用戶以讀寫模式操作鏡像文件結束后再將新的鏡像文件同步至存儲層,覆蓋已有的目標文件。聚合存儲狀態下小文件的同步只能采用全量上傳,而這里的覆蓋操作是指在SMDFS存儲層重新寫入小文件數據并更新元數據和相關索引,并將原有的數據段標記為刪除,等待后臺回收數據存儲空間。

圖1 數據暫存區文件流重定向模型Fig.1 File flow redirection model in temporary data cache
用戶文件讀操作時,如果數據暫存區存在目標文件鏡像,POSIX兼容層直接讀取鏡像文件。若不存在,則對讀取的遠程目標文件執行熱點判斷,符合熱點標準則先將遠程文件流重定向到數據暫存區進行熱點數據緩存,否則直接將文件流返回給用戶。數據暫存區的文件流重定向能減少遠程過程調用(Remote Procedure Call,RPC),降低網絡開銷,實現用戶操作的快速響應。
異步上傳操作能避免用戶線程阻塞,有效控制鏡像文件同步操作的系統資源占用量,提高系統效率,因此,本文基于數據暫存區提出異步線程池[9-10]文件同步模型。
如圖2所示,用戶層對鏡像文件的寫操作結束后,POSIX兼容層根據目標文件的路徑信息創建上傳任務,并將其加入上傳隊列。上傳隊列中的任務由異步線程池中的異步上傳線程處理。當上傳任務被成功創建后,會喚醒線程池中的異步上傳線程執行上傳任務。為避免系統的突發故障導致任務丟失,在數據暫存區創建上傳任務加入隊列的同時,會將任務同時寫入日志記錄文件中作持久化處理,同時維護一個任務執行的日志來記錄任務對應的結果。當客戶端或系統故障時,在系統重啟后的初始化操作中會自動整理任務的執行情況,并自動對未執行或未執行成功的任務啟動上傳。

圖2 異步線程池文件同步模型Fig.2 Asynchronous thread pool model for file synchronization
異步線程池同步模型可以有效控制系統資源占用量,提高文件并發寫的效率;但是,異步線程的使用帶來了并發控制的難題。當鏡像文件處于上傳的同時,如果鏡像文件需要被覆寫,就會產生同一個文件的讀寫沖突,致使系統故障。本文采用覆寫中斷并發控制技術解決上述讀寫沖突問題。
為保證覆寫線程和異步上傳線程關于目標鏡像文件的讀寫互斥,一個簡單的處理方法就是等待上傳線程將目標文件同步完成后,覆寫線程再進行操作。然而這種模式存在明顯的缺陷,即當上傳文件較大時,覆寫線程會長時間等待,影響系統效率,降低SMDFS的用戶體驗。在SMDFS系統的實際應用環境中,對于同一文件的連續覆蓋只需保存最終版本。因此,在此場景中使用覆寫中斷技術會有效提高系統效率。
覆寫中斷并發控制技術通過0-1同步信號量實現覆寫線程和異步線程的并發控制。
對于異步上傳線程而言,當任務處于上傳狀態時,將同步信號量初始化為0,然后開始任務上傳。上傳過程中若覆寫線程要獲取該任務鏡像文件的寫權限,需先將任務狀態置為中斷狀態并將線程睡眠,等待異步線程響應。異步上傳線程在同步數據時監聽到任務狀態被置成中斷狀態時,將上傳任務取消并喚醒等待中的覆寫線程讓其繼續后續的文件覆寫操作。覆寫中斷的操作能減少不必要的線程開銷,加快系統對用戶的響應。
基于數據暫存區的元數據高效緩存技術包括數據緩存與元數據緩存綁定管理技術、元數據緩存的組織、基于目錄的元數據緩存與淘汰策略、元數據緩存的一致性控制。
SMDFS為實現海量小文件的高效存儲,會對同時寫入系統的一批文件的元數據緩沖并批量上傳,這一操作減少了大量的RPC操作,有效節省了網絡帶寬。但是,對SMDFS Linux客戶端而言,文件創建操作結束后會立即調用Exist操作來判斷文件是否創建成功,此時,若元數據依然處于緩沖等待狀態則會導致系統誤報,因此,SMDFS客戶端設計元數據緩存來實現對文件狀態的高效管理與維護。
SMDFS引入數據暫存區后,對于文件的讀寫訪問、權限控制、刪除、元數據緩存一致性控制等操作都會涉及對數據暫存區中鏡像文件的LOOKUP操作。LOOKUP操作與最終目標文件的查找以及掛載點處理等操作相關聯,系統資源開銷較大。為方便系統管理以及節約系統資源,SMDFS對數據緩存與元數據緩存綁定管理,將數據暫存區的每個鏡像文件的屬性記錄在元數據緩存中對應的項中。當客戶端需要檢索數據暫存區是否存在目標文件的鏡像文件時,可以直接將數據緩存對磁盤存儲的LOOKUP操作轉化為對內存中元數據緩存信息的訪問,進而提高LOOKUP操作效率。
元數據組織與訪問效率與分布式文件系統性能緊密相關。SMDFS采用跳表進行元數據的組織與管理。跳表[11]的效率與紅黑樹[12]旗鼓相當,可以實現元素的快速檢索、插入、刪除等操作。但使用跳表能高度還原用戶的目錄結構視圖,實現高效的目錄List操作。在SMDFS的POSIX兼容層中,首先,基于文件路徑構建跳表節點索引,并為每個目錄添加內容索引項,按照廣度遍歷優先的順序將文件元數據緩存至跳表。因此,同目錄下文件的元數據會連續地分布在跳表中某一段區域,并且目錄的內容索引項位于該目錄下所有文件元數據緩存項的最前面。在執行List操作時,只需先檢索到該目錄的內容索引項,再向后連續訪問,即可獲取該目錄下所有文件的元數據。
對于文件系統上層應用而言,目錄的List操作屬于頻繁的用戶操作。另外,基于局部性原理,當一個文件被訪問時,同目錄下的文件很可能被訪問到。針對這種情況,對元數據緩存采取基于目錄的緩存策略。
對于某個目錄下的文件第一次被訪問時,將該目錄下所有文件的元數據都存儲到元數據緩存中,當用戶執行List操作或者訪問同目錄下文件時,文件系統可以極快地響應用戶操作。但是,系統需要對內存中元數據緩存的規模加以控制,在實際應用中需要設置元數據緩存的目錄緩存上限和元數據緩存項數目上限,同時通過設置基于目錄的策略來進行元數據緩存的置換,可以根據實際需求采用最近最久未使用算法(Least Recently Used,LRU)、先進先出算法(First Input First Output,FIFO)等置換策略。
在文件系統中,稱一個存在海量文件的目錄為大目錄。基于目錄的元數據的緩存策略在處理大目錄結構時存在嚴重的技術缺陷,因為可能一個大目錄下的文件數目就超過了元數據緩存項上限。針對大目錄結構做元數據緩存的代價過大,因此,在實際的緩存中針對大目錄采取基于目錄下目標文件的緩存策略以提高緩存的利用率。
POSIX兼容層啟動覆寫中斷直到異步上傳線程完成最新鏡像文件同步期間,會因為中斷文件的不完整導致SMDFS存儲層文件元數據與POSIX兼容層不一致。如果這期間觸發存儲層到緩存的元數據更新操作,將導致元數據緩存的對應數據變為“臟”數據。針對這一問題,本文設計了基于事件和定時器雙重控制的元數據更新策略。如圖3所示,對于元數據緩存來說,僅當接收到來自用戶層對目標目錄的訪問事件時,才觸發元數據緩存更新檢查。若目標目錄緩存超時,才會進一步觸發元數據的更新操作。由于文件覆寫時元數據緩存中保存的是最新鏡像文件的元數據,所以元數據緩存更新操作會過濾掉文件暫存區鏡像文件對應的緩存元數據以保證元數據緩存中數據的有效性。

圖3 元數據更新流程Fig.3 Metadata update flow
我們基于課題組海量小文件系統SMDFS,實現了POSIX接口兼容的分布式文件系統SMDFS3.0,并支持Linux端的遠程掛載。
測試環境由9臺通用服務器組成,其中1個元數據節點、3個數據節點,5個Linux客戶端。其中分布式文件系統集群的硬件配置為:長城銀河服務器EF420,CPU型號為飛騰FT-1500A,內存64 GB,硬盤48 TB,操作系統為中標麒麟。Linux客戶端環境為超微2027TR-H71RF服務器,CPU型號為Xeon E5-2600V2,內存 64 GB,硬盤 12 TB,操作系統為 Centos6.7。
隨機寫測試客戶端為 ThinkPad S5,CPU型號為 I7-6700HQ,內存4 GB,硬盤1 TB,操作系統為Centos6.7。
測試網絡環境為千兆網,測試采用的小文件大小為100 KB。
為測試文件系統的元數據緩存性能以及Linux客戶端讀寫性能,針對 SMDFS2.0、實現POSIX兼容海量小文件系統SMDFS3.0以及HDFS進行以下測試:
1)元數據緩存性能對比測試。向文件系統存儲層4個不同的目錄各自寫入5 000、10 000、30 000、50 000個文件,分別對有無元數據緩存的SMDFS3.0進行掛載,然后記錄測試目錄List操作從執行到響應的時間,比較性能差異。測試結果如圖4所示。

圖4 元數據緩存目錄List性能對比實驗Fig.4 Comparative experiments on List operation performance in metadata cache
2)文件系統隨機寫性能測試。使用測試工具iozone分別測試本地文件系統(LocalFS)和SMDFS3.0,參數為10線程,文件大小為1 GB,記錄大小為4 KB。測試結果如圖5所示。

圖5 隨機寫性能測試實驗Fig.5 Performance experiments on random write
3)文件系統讀寫性能測試與HDFS以及SMDFS2.0進行對比。由于 SMDFS2.0不支持遠程掛載,實驗中測試SMDFS3.0、HDFS 通過 FUSE(Filesystem in Userspace)掛載后的Linux客戶端性能以及SMDFS2.0的Java接口性能。比較SMDFS3.0與HDFS的客戶端讀寫性能以及SMDFS3.0 Linux客戶端相對于SMDFS2.0 Java接口的性能損耗。分布式集群初始裝載1000萬個文件,對5個客戶端同時進行以下測試:
a)每個客戶端單線程,每個線程從集群1 000萬文件中隨機下載1萬個文件,5個客戶端累計下載5萬個文件,記錄單個文件平均讀延時。
b)每個客戶端10個線程,每個線程從集群1000萬文件中隨機下載5000個文件,5個客戶端累計下載25萬個文件,記錄單個文件平均讀延時。
c)每個客戶端單線程,每個線程從集群某個目錄下順序下載1萬個文件,5個客戶端累計下載5萬個文件,記錄單個文件平均讀延時。
d)每個客戶端10個線程,每個線程從集群某個目錄下順序下載1萬個文件,5個客戶端累計下載50萬個文件,記錄單個文件平均讀延時。
e)每個客戶端單線程,每個線程向集群寫入2萬個文件,5個客戶端累計上傳10萬個文件,記錄單個文件平均寫延時。
f)每個客戶端10個線程,每個線程向集群寫入1萬個文件,5個客戶端累計上傳50萬個文件,記錄單個文件平均寫延時。
實驗結果如圖6所示。

圖6 文件系統讀寫性能對比測試Fig.6 Comparative experiments on reading andwriting performance of some file systems
總結比較實驗結果可以發現,設置元數據緩存的情況下,第一次調用某目錄List操作前會先裝載該目錄下元數據,再由本地元數據緩存接管后續目錄的List操作,減少了RPC調用。因此,設置元數據緩存的情況下,List操作性能有明顯提升。整體來說,Linux客戶端元數據緩存的設計將目錄的List操作性能提高了近10倍。根據隨機寫性能測試結果可以發現,SMDFS3.0的隨機寫性能大約為本地文件系統隨機寫性能的20%。對比文件系統讀寫性能測試結果,基于FUSE掛載的SMDFS3.0相比HDFS的Linux客戶端,隨機讀性能有10倍以上的性能提升,順序讀和順序寫性能有約3~4倍的提升。但是,由于FUSE掛載后會引入額外的內核態和用戶態切換等帶來的開銷,因此SMDFS3.0的Linux客戶端相對于系統的Java接口會有大約50%的性能損耗。
SMDFS不兼容POSIX約束,無法直接兼容傳統B/S、C/S應用,在實際應用上也無法支持文件的任意編輯。本文提出的基于本地緩存的POSIX兼容技術,利用Linux本地文件系統POSIX兼容的特性,通過對用戶層和存儲層的文件流作重定向處理實現系統的POSIX兼容。同時,針對SMDFS的文件存儲業務設計了基于目錄的元數據緩存,提高了系統效率。但是,系統的POSIX兼容特性依賴于本地文件系統空間,在處理大文件時性能會隨著文件大小增長而下降。這也是下一步需要考慮和解決的問題。