馬 振,哈力旦·阿布都熱依木,李希彤
新疆大學(xué) 電氣工程學(xué)院,烏魯木齊 830047
樣本數(shù)據(jù)集具有文件類型多樣、數(shù)量大但單個文件體積小、文件名重復(fù)度和類似度高等特點(diǎn),使Hadoop分布式文件系統(tǒng)(Hadoop Distributed Files System,HDFS)在存儲樣本數(shù)據(jù)集時(shí)面臨巨大挑戰(zhàn),這些挑戰(zhàn)主要在主節(jié)點(diǎn)內(nèi)存消耗、元數(shù)據(jù)管理、存儲性能等方面[1-2]。
針對分布式文件系統(tǒng)HDFS在處理海量小文件時(shí)效率不高的問題,已有的解決方案如下:
(1)游小容等人[3]提出了一種基于Hadoop的海量教育資源小文件的存儲方案,其利用教育資源小文件之間的前驅(qū)后繼關(guān)系將小文件歸類合并成大文件,具體方案參見文獻(xiàn)[3]。該方案沒有通過實(shí)驗(yàn)給出設(shè)定小文件判斷條件的依據(jù),且存在一個文件占據(jù)兩個數(shù)據(jù)塊的問題。
(2)Sethia等人[4]提出了一種新的OMSS算法(基于優(yōu)化MapFile的小文件存儲),其將小文件合并成MapFile,具體方案參見文獻(xiàn)[4]。該方案使用了MapFile的合并文件格式,并未建立所有小文件索引,僅在一定程度上提高了讀取效率。
(3)鄭通等人[5]提出了將小文件合并為大文件,同時(shí)將小文件到大文件的映射關(guān)系存于HBase中,具體方案參見文獻(xiàn)[5]。該方案采用文件名作為行鍵,并未考慮HBase的訪問熱點(diǎn)問題,而且沒有考慮緩存穿透問題。
針對以上方案存在的一些問題及樣本數(shù)據(jù)集的特點(diǎn),本文提出了一種面向樣本數(shù)據(jù)集的存取優(yōu)化方案。方案中考慮了樣本數(shù)據(jù)集的高度相關(guān)性以及緩存穿透問題。
為了保持樣本數(shù)據(jù)集的高度相關(guān)性和存儲空間合理化,設(shè)計(jì)用戶端和HDFS端的樣本數(shù)據(jù)集目錄結(jié)構(gòu)如圖1、圖2所示。
圖1 用戶端目錄結(jié)構(gòu)
圖2 HDFS端目錄結(jié)構(gòu)
本文提出的方案由用戶客戶端、數(shù)據(jù)處理模塊、Hadoop分布式文件系統(tǒng)三部分構(gòu)成,總架構(gòu)如圖3所示。各部分功能說明如下:
(1)客戶端接入模塊:該模塊用于用戶與Hadoop分布式文件系統(tǒng)的存取交互,并實(shí)現(xiàn)了遠(yuǎn)程任務(wù)提交功能。
(2)數(shù)據(jù)處理模塊:該模塊實(shí)現(xiàn)了數(shù)據(jù)合并處理、索引構(gòu)建、數(shù)據(jù)預(yù)取和緩存的功能。
圖3 樣本數(shù)據(jù)集存儲架構(gòu)
(3)Hadoop分布式文件系統(tǒng)[6-7]:該模塊實(shí)現(xiàn)海量樣本數(shù)據(jù)集的存儲,采用HBase非結(jié)構(gòu)化數(shù)據(jù)庫[8-9]存儲小文件索引。
樣本數(shù)據(jù)集的存取過程具有一次寫入、多次讀取的特點(diǎn),對讀取性能的要求高于寫入性能,同時(shí)文件增減替換時(shí)需要不影響存取的效率。
樣本數(shù)據(jù)集有圖片數(shù)據(jù)集、文本數(shù)據(jù)集、音頻數(shù)據(jù)集和視頻數(shù)據(jù)集等。由于Hadoop并未提供區(qū)分大、小文件的判定條件,且不同硬件配置的文件系統(tǒng)對大、小文件判定條件具有一定的影響。因此,本文通過分析Hadoop性能測試工具TestDFSIO寫入不同大小文件時(shí)的性能,確定文件系統(tǒng)對應(yīng)的大、小文件判定條件。為了向數(shù)據(jù)集添加和替換小文件,統(tǒng)計(jì)數(shù)據(jù)集中占比最高的文件大小,將此文件大小設(shè)置為預(yù)留區(qū)域。將數(shù)據(jù)塊減去預(yù)留區(qū)域大小與合并文件頭大小之和作為合并閾值,即
2.1.1 變尺度堆棧算法
本文提出一種基于數(shù)據(jù)塊均勻[10]的合并算法,其核心思想是借鑒堆、棧中數(shù)據(jù)遵循先進(jìn)先出(First In First Out,F(xiàn)IFO)和先進(jìn)后出(First-In Last-Out,F(xiàn)ILO)的原則[11-12],改變堆、棧的尺度,并交叉應(yīng)用到小文件合并的過程,故將其命名為變尺度堆棧算法(Variable Scale Stack Algorithm,VSSA)。算法詳細(xì)步驟如下:
步驟1 FIFO合并過程。
按小文件的體積從大到小進(jìn)行排序,以迭代的方法選擇最大的i個文件進(jìn)行合并,直至放入第i+1個文件時(shí)超出設(shè)定合并閾值時(shí)退出此過程,并將此i個文件從文件列表中刪除。
步驟2 FILO條件判斷。
計(jì)算最小文件體積與合并閾值的差值,若為負(fù)值,則轉(zhuǎn)到步驟3;若為正值,則轉(zhuǎn)到步驟4。
步驟3 FILO合并過程。
迭代選取最小體積的 j個文件追加到步驟1產(chǎn)生的合并文件中,直至放入第i+j+1個文件時(shí)超出設(shè)定閾值,并將此 j個文件從文件列表內(nèi)刪除,轉(zhuǎn)到步驟4。
步驟4將選取的文件送入合并模塊中,未合并的文件更新為新的輸入列表。重復(fù)步驟1~步驟4,直至將所有小文件進(jìn)行合并。
2.1.2 算法實(shí)現(xiàn)過程
用戶通過客戶端向HDFS提交存儲任務(wù)時(shí),首先根據(jù)測得的大、小文件判定條件T將樣本數(shù)據(jù)集分為大文件和小文件。以圖片數(shù)據(jù)集為例,若為大文件,則無需合并,直接將其上傳至HDFS的該用戶下該樣本數(shù)據(jù)集對應(yīng)的文件夾中。若為小文件,則通過VSSA算法在該數(shù)據(jù)集中選取最優(yōu)文件組合合并,直至合并文件體積達(dá)到合并閾值,將合并文件上傳至HDFS的該用戶下該樣本數(shù)據(jù)集對應(yīng)的文件夾中。將樣本數(shù)據(jù)集的名稱縮寫和上傳時(shí)間作為合并文件的命名方式,例如圖片測試集(Image Test Set)ITS20180423123357。合并過程的流程圖如圖4所示,其他數(shù)據(jù)集類似于圖片數(shù)據(jù)集的合并方式。圖5為合并文件結(jié)構(gòu)圖。
圖4 合并過程流程圖
圖5 合并文件結(jié)構(gòu)圖
為了快速檢索合并文件中的小文件,本文在每次創(chuàng)建合并文件時(shí),將記錄小文件名、小文件所在數(shù)據(jù)塊ID及其在合并文件中的偏移量存于臨時(shí)索引文件中,在上傳過程完成之后,再讀取此臨時(shí)索引文件中的信息存儲于HBase表中。對于合并文件,將記錄文件名和數(shù)據(jù)塊ID。對于大文件,則記錄該文件的文件名和存儲路徑。
由于樣本數(shù)據(jù)集中存在大量不同路徑文件名相同、相同路徑文件名類似的文件,例如COCO_train2014_000000000110.jpg,COCO_train2014_000000000562.jpg。隨著文件數(shù)目的遞增,以文件名作為Row Key,將會造成訪問熱點(diǎn)問題[13]和行鍵重復(fù)問題。為此,本文方案將文件MD5值、文件名、樣本數(shù)據(jù)集名結(jié)合作為Row Key,將文件標(biāo)志、小文件和合并文件的數(shù)據(jù)塊ID、大文件存儲路徑、小文件在合并文件中的偏移量存于索引表中。文件為大文件,將文件標(biāo)記為b;文件為小文件,則文件標(biāo)記為s;文件為合并文件,則文件標(biāo)記為m。以此標(biāo)志對應(yīng)不同的讀取數(shù)據(jù)方法。HBase中的索引存儲結(jié)構(gòu)如表1所示。
表1 HBase索引存儲結(jié)構(gòu)
由于樣本數(shù)據(jù)集的高度相關(guān)性,當(dāng)用戶訪問樣本數(shù)據(jù)集時(shí),需要大量向NameNode發(fā)送大量獲取文件元數(shù)據(jù)的請求,將給主節(jié)點(diǎn)帶來巨大的壓力。本文采用預(yù)先讀取的策略,在客戶端上搭建Ehcache緩存框架[14],將樣本數(shù)據(jù)集的元數(shù)據(jù)信息緩存至客戶端內(nèi)存中。
其核心思想為:用戶訪問某個樣本數(shù)據(jù)集的文件時(shí),在讀取該文件索引的同時(shí),將該數(shù)據(jù)集下所有的文件索引信息緩存在客戶端內(nèi)存中。當(dāng)用戶多次查詢不存在的文件時(shí),導(dǎo)致每次都要去HBase和NameNode查詢。為此,本文對查詢?yōu)榭盏慕Y(jié)果進(jìn)行緩存,設(shè)置緩存時(shí)間為5分鐘,再次查詢時(shí),在當(dāng)前緩存時(shí)間上增加1分鐘,避免多次訪問不存在文件時(shí)而導(dǎo)致的緩存穿透問題。在24小時(shí)內(nèi)沒有用戶訪問該樣本數(shù)據(jù)集時(shí),則將其索引信息從緩存中清除。
當(dāng)用戶向客戶端發(fā)起讀取數(shù)據(jù)的任務(wù)時(shí),客戶端首先獲取該用戶的HBase數(shù)據(jù)表,根據(jù)文件名和樣本數(shù)據(jù)集名在緩存索引表中檢索是否存在對應(yīng)的文件元數(shù)據(jù)。若不存在,使用原始HDFS讀取數(shù)據(jù)的方法。若存在,判斷其文件標(biāo)志:為b,則使用大文件讀取模式(B Mode)獲取該文件;為m,則使用合并文件讀取模式(M Mode)獲取該文件;為s,則使用小文件讀取模式(S Mode)獲取該文件。
B Mode:結(jié)合HBase表中獲取的文件存儲路徑及原始HDFS讀取單個文件的方法,便可讀取該大文件。
M Mode:結(jié)合HBase表中獲取的數(shù)據(jù)塊ID,便可讀取該合并文件。
S Mode:結(jié)合HBase表中獲取的數(shù)據(jù)塊ID和偏移量,可確定小文件所在的數(shù)據(jù)塊的準(zhǔn)確位置,便可快速讀取該小文件。
詳細(xì)讀取過程流程圖如圖6所示。
圖6 讀取過程流程圖
用戶添加文件時(shí)參考上述方法。若為小文件,則遵循優(yōu)先向最小合并文件追加的原則,并構(gòu)建索引存儲至該用戶的HBase表中。若為大文件,則直接存儲至HDFS,并向該用戶的HBase表中添加索引信息。
用戶刪除文件時(shí),首先根據(jù)文件名和樣本數(shù)據(jù)集名在HBase表中查找該文件的索引信息,將此索引標(biāo)記為待刪除。若為小文件,定位小文件的位置并將其刪除,最后將標(biāo)記索引刪除,將剩下的文件合并和更新索引信息。若為大文件,則將大文件和標(biāo)記索引先后刪除。
用戶替換文件時(shí),首先根據(jù)文件名和樣本數(shù)據(jù)集名在HBase表中查找該文件的索引信息。若為小文件,將此數(shù)據(jù)塊內(nèi)的文件索引標(biāo)記為替換,并用新文件替換此小文件,最后更新所有標(biāo)記的索引信息。若為大文件,將文件的索引信息標(biāo)記為替換,刪除舊文件,并將新文件存儲至對應(yīng)的位置。最后更新大文件的索引信息。
實(shí)驗(yàn)使用Apache Ambari[15]部署了3個節(jié)點(diǎn)的集群環(huán)境,各節(jié)點(diǎn)操作系統(tǒng)均為Centos 7,Hadoop版本為Hadoop 2.7.2,開發(fā)環(huán)境為Eclipse 4.6,節(jié)點(diǎn)采用SSH(Secure Shell)免密碼配置,數(shù)據(jù)塊的副本數(shù)量為2。各節(jié)點(diǎn)機(jī)器詳細(xì)配置見表2。
表2 各節(jié)點(diǎn)機(jī)器詳細(xì)配置
本次實(shí)驗(yàn)從多個公開數(shù)據(jù)集的訓(xùn)練集和測試集中隨機(jī)選取200 000個文件作為測試數(shù)據(jù)集,并保持公開數(shù)據(jù)集的目錄結(jié)構(gòu)。公開數(shù)據(jù)集有cocodataset2017(http://cocodataset.org/#download,大規(guī)模的物體檢測、分割和字幕數(shù)據(jù)集),Stanford Car Dataset[16](http://ai.stanford.edu/~jkrause/cars/car_dataset.html,汽車圖像數(shù)據(jù)集),Daimler Pedestrian Benchmark Data Set(http://www.gavrila.net/Datasets/Daimler_Pedestrian_Benchmark_D/Daimler_Pedestrian_Segmentatio/daimler_pedestrian_segmentatio.html,Daimler行人視頻數(shù)據(jù)),THUYG-20(http://www.openslr.org/22/,維吾爾語語音數(shù)據(jù)庫),The WikiText Long Term Dependency Language Modeling Dataset(https://einstein.ai/research/the-wikitext-longterm-dependency-language-modeling-dataset,基于 Wikipedia的長期依賴語言模型數(shù)據(jù)集)。其中1 KB~100 KB的文件占10%,100 KB~17 MB的文件占80%,17 MB以上的文件占10%。分5組進(jìn)行實(shí)驗(yàn),每組的文件數(shù)量為40 000、80 000、120 000、160 000、200 000。
將2 GB數(shù)據(jù)平均分為200 KB、700 KB、1 MB、5 MB、10 MB、13 MB、15 MB、16 MB、17 MB、17.5 MB、18 MB、18.5 MB、19 MB、19.5 MB、20 MB、25 MB、30 MB、35 MB、40MB大小的文件,使用Hadoop性能測試工具TestDFSIO測試寫入不同大小文件的性能,得到相應(yīng)的Throughput和Average IO Rate,結(jié)果如圖7所示。因此,設(shè)置17 MB為大、小文件判定條件T進(jìn)行后續(xù)的實(shí)驗(yàn)。
圖7 不同文件大小下的處理性能
為了驗(yàn)證本文方案與原HDFS、SequenceFile[17]方案在上傳速度方面的差異,將5組數(shù)據(jù)分別通過改進(jìn)方案與原HDFS、SequenceFile方案上傳到HDFS。每組進(jìn)行3次實(shí)驗(yàn),取平均值進(jìn)行分析,結(jié)果如圖8所示。
圖8 寫入時(shí)間對比
由實(shí)驗(yàn)結(jié)果可知,本文方案和SequenceFile方案均優(yōu)于原HDFS上傳方式。因?yàn)樵璈DFS頻繁地向NameNode發(fā)送請求,NameNode響應(yīng)占用了大量時(shí)間。而本文方案和SequenceFile方案將多個文件合并上傳至HDFS,NomeNode僅響應(yīng)一次。但本文方案在上傳的同時(shí)還要向HBase寫入索引信息,因此比較耗時(shí)。
為了驗(yàn)證本文方案在主節(jié)點(diǎn)的內(nèi)存占用率優(yōu)化程度,設(shè)計(jì)本文方案與原HDFS的實(shí)驗(yàn)進(jìn)行對比。記錄每組文件上傳之后的內(nèi)存變化,每組進(jìn)行3次實(shí)驗(yàn),取平均值進(jìn)行分析,結(jié)果如圖9所示。
圖9 內(nèi)存占用對比
由圖9可知,本文方案在緩解NameNode內(nèi)存壓力方面優(yōu)于原HDFS。主要原因是本文方案采取先將文件合并再上傳的方法,大大減少了數(shù)據(jù)塊的數(shù)量和NameNode管理的文件數(shù)量,從而降低了主節(jié)點(diǎn)的內(nèi)存消耗。
為了驗(yàn)證本文方案在文件讀取方面的優(yōu)勢,按照相同的步驟對本文方案和原HDFS、SequenceFile方案進(jìn)行實(shí)驗(yàn)。根據(jù)文件名和樣本數(shù)據(jù)集名讀取文件并記錄時(shí)間,每組進(jìn)行3次實(shí)驗(yàn),取平均值進(jìn)行分析,結(jié)果如圖10所示。
圖10 文件讀取時(shí)間對比
從圖10文件讀取時(shí)間的比較可知,本文改進(jìn)方案在文件讀取方面優(yōu)于原HDFS和SequenceFile方案。由于原HDFS和SequenceFile方案讀取文件時(shí)均會向NameNode發(fā)送大量獲取文件元數(shù)據(jù)的請求。而本文方案加入了基于Ehcache的緩存框架的預(yù)取機(jī)制,將正在訪問的數(shù)據(jù)集元數(shù)據(jù)信息預(yù)取至客戶端內(nèi)存中,減少了向NameNode發(fā)送請求的次數(shù),從而提高了文件的讀取速度。隨著文件數(shù)量的遞增,本文方案將呈現(xiàn)更加明顯的優(yōu)勢。
本文考慮了樣本數(shù)據(jù)集的高度相關(guān)性,提出了一種面向樣本數(shù)據(jù)集存取優(yōu)化方案,并優(yōu)化了樣本數(shù)據(jù)集的寫入、讀取、添加、刪除和替換方法。本文方案使用Hadoop分布式系統(tǒng)架構(gòu),利用分布式文件系統(tǒng)HDFS的高吞吐量的優(yōu)點(diǎn)存儲樣本數(shù)據(jù)集,并對其存取方式進(jìn)行優(yōu)化。首先根據(jù)機(jī)器配置上文件系統(tǒng)對應(yīng)的大、小文件判定條件,將樣本數(shù)據(jù)集分為大文件和小文件,使用變尺度堆棧算法優(yōu)化小文件合并過程,構(gòu)建所有文件的索引并存儲在HBase中,優(yōu)化HBase的行鍵,將正在訪問的樣本數(shù)據(jù)集元數(shù)據(jù)緩存于客戶端內(nèi)存中。通過實(shí)驗(yàn)對比,本文方案在存儲文件、讀取文件以及降低主節(jié)點(diǎn)內(nèi)存消耗方面均有明顯的改善。