侯向?qū)?/p>
(成都理工大學(xué) 工程技術(shù)學(xué)院,四川 樂山 614007)
面對海量的車牌數(shù)據(jù),傳統(tǒng)的基于終端的車牌識別系統(tǒng)受到很大的挑戰(zhàn)。Hadoop云計(jì)算平臺具有強(qiáng)大的海量數(shù)據(jù)分發(fā)、存儲以及對大數(shù)據(jù)進(jìn)行并行運(yùn)算的能力,是大數(shù)據(jù)處理領(lǐng)域的首選。HDFS和MapReduce是Hadoop框架的核心,然而,HDFS設(shè)計(jì)的初衷是為了能夠存儲和分析大文件,并且在實(shí)際應(yīng)用中取得好的效果,但卻不適合處理大小在10 KB~1 MB的海量車牌圖像小文件。這是因?yàn)镠DFS集群下每一個小文件均占據(jù)一個Block,海量的小文件會消耗大量NameNode內(nèi)存,另外,Hadoop會為每個文件啟動一個Map任務(wù)來處理,大量的時(shí)間花費(fèi)在啟動和關(guān)閉Map任務(wù)上,從而嚴(yán)重降低了執(zhí)行速率。因此,Hadoop在存儲和處理海量小文件時(shí),存儲效率和性能會大幅下降。
文中在分析現(xiàn)有解決方案的基礎(chǔ)上,利用CFIF將小文件打包分片,以解決HDFS在存儲海量小文件時(shí)的瓶頸問題,以及MapReduce的執(zhí)行效率問題。
HDFS(Hadoop distributed file system)[1-3]是用Java開發(fā)的能夠運(yùn)行在通用機(jī)器上的具有高容錯性、高吞吐量的分布式文件系統(tǒng)。HDFS基于M/S模式,由一個NameNode節(jié)點(diǎn)和若干DataNode節(jié)點(diǎn)構(gòu)成。NameNode是主控服務(wù)器,其職責(zé)是維護(hù)HDFS命名空間,協(xié)調(diào)客戶端對文件的訪問和操作,管理元數(shù)據(jù)并記錄文件數(shù)據(jù)在每個DataNode節(jié)點(diǎn)上的位置和副本信息[4-6]。DataNode是數(shù)據(jù)存儲節(jié)點(diǎn),在NameNode的調(diào)度下,負(fù)責(zé)客戶端的讀寫請求以及本節(jié)點(diǎn)的存儲管理[7-8]。
(1)NameNode內(nèi)存瓶頸。
HDFS中所有元數(shù)據(jù)信息都存儲在NameNode內(nèi)存中。HDFS在設(shè)計(jì)時(shí),每一個文件、文件夾和Block大約占150 Byte。假設(shè)HDFS集群中有100萬個小文件,每一個小文件均占據(jù)一個Block,就至少需要3G內(nèi)存[9]。所以,海量的小文件會占用大量NameNode內(nèi)存,造成NameNode內(nèi)存的嚴(yán)重浪費(fèi),極大限制了集群中文件數(shù)量的規(guī)模,成為HDFS文件系統(tǒng)的一大瓶頸。
(2)數(shù)據(jù)訪問效率低。
在M/S模式下,所有的數(shù)據(jù)讀寫請求大都要經(jīng)過NameNode,當(dāng)存儲海量小文件時(shí),NameNode會頻繁地接受大量地址請求和處理數(shù)據(jù)塊的分配。此外,海量小文件一般分儲于不同的DataNode上,訪問時(shí)要不斷地從一個DataNode切換到另一個DataNode,嚴(yán)重影響了訪問效率和性能[10-11]。此外,客戶端在讀取海量小文件時(shí),需要與NameNode節(jié)點(diǎn)頻繁通信,極大降低了元數(shù)據(jù)節(jié)點(diǎn)的I/O性能。最后,讀取海量小文件時(shí),由于小文件存儲空間連續(xù)性不足,HDFS順序式文件訪問的優(yōu)勢難以發(fā)揮。
(3)MapReduce運(yùn)行效率低。
Hadoop處理海量小文件時(shí),會為每一個小文件啟動一個Map任務(wù),因此,大量時(shí)間浪費(fèi)在Map任務(wù)的啟動和關(guān)閉上,嚴(yán)重降低了執(zhí)行速率。
處理小文件一直是Hadoop的一大難題。目前,解決問題的常見方案大致有:Hadoop Archives方案、Sequence File方案、MapFile方案和HBase方案[11-13]。
Hadoop Archives即HAR,是Hadoop系統(tǒng)自帶的一種解決方案[14]。其原理是先把文件打包,然后做上標(biāo)記以便查詢。HAR的缺點(diǎn)是兩級索引增加了系統(tǒng)搜索和處理文件的時(shí)間,HAR沒有對文件進(jìn)行合并,文件的數(shù)量沒有明顯減少。這一方面會耗費(fèi)NameNode內(nèi)存,另一方面MapReduce要給每個小文件各啟動一個Map任務(wù),總的Map任務(wù)數(shù)并沒有減少,因此在MapReduce上運(yùn)行時(shí)效率很低。
Sequence File基于文件合并,它把多個小文件歸并成一個大文件,通過減少文件數(shù)來減輕系統(tǒng)的內(nèi)存消耗和性能。但是它沒有設(shè)置索引方式,導(dǎo)致每次查找合并序列中的小文件都要從整個系統(tǒng)的磁盤中去查找,嚴(yán)重影響了系統(tǒng)的效率。
MapFile是排序后的Sequence File,MapFile由索引文件(Index)和數(shù)據(jù)文件(Data)兩大部分構(gòu)成。Index作為文件的數(shù)據(jù)索引,主要記錄了每個小文件的鍵值,以及該小文件在大文件中的偏移位置。其缺點(diǎn)是當(dāng)訪問MapFile時(shí),索引文件會被加載到內(nèi)存,因此會消耗一部分內(nèi)存來存儲Index數(shù)據(jù)。
HBase以MapFile方式存儲數(shù)據(jù),通過文件合并與分解提高文件的存儲效率[15]。其缺點(diǎn)主要是:HBase規(guī)定數(shù)據(jù)的最大長度是64 KB,因此不能存儲大于64 KB的小文件。另外, HBase只支持字符串類型,要存儲圖像、音頻、視頻等類型還需用戶做相關(guān)的處理。還有,隨著文件數(shù)的增多,HBase需要進(jìn)行大量的合并與分解操作,這樣既占用系統(tǒng)資源又影響系統(tǒng)性能[13]。
總之,通過對以上常用方案的分析,發(fā)現(xiàn)都不適合解決海量車牌圖像的存儲與執(zhí)行效率問題。因此,下節(jié)將采用另外一種方案來解決當(dāng)前所面臨的困境。
Hadoop在新版本中引入了CombineFileInputFormat(簡稱CFIF)抽象類[16],其原理是利用CFIF將來自多個小文件的分片打包到一個大分片中,這種打包只是邏輯上的組合,讓Map以為這些小文件來自同一分片,每個大分片只啟動一個Map任務(wù)來執(zhí)行,通過減少M(fèi)ap任務(wù)的啟動數(shù)量,節(jié)省了頻繁啟動和關(guān)閉大量Map任務(wù)所帶來的性能損失,提高了處理海量小文件的效率。另外,CFIF在將多個小文件分片打包到一個大分片時(shí)會充分考慮數(shù)據(jù)本地性,因此節(jié)省了數(shù)據(jù)在節(jié)點(diǎn)間傳輸所帶來的時(shí)間開銷。
CFIF只是一個抽象類,并沒有具體的實(shí)現(xiàn),需要自定義。文中利用CFIF處理海量車牌小文件,具體流程設(shè)計(jì)如圖1所示。
由圖1可知,要利用CFIF來實(shí)現(xiàn)海量車牌圖像小文件的處理,需要做如下工作:
(1)設(shè)計(jì)Hadoop圖像接口類,因?yàn)镠adoop沒有提供圖像處理接口,不能處理圖像文件數(shù)據(jù),因此必須自己定義。
(2)繼承CFIF類,定義CombineImageInputFormat類將海量圖像小文件打包成分片,作為MapReduce的輸入格式。
(3)實(shí)現(xiàn)CombineImageRecordReader,它是CombineFileSplit的通用RecordReader,就是為來自不同文件的分片創(chuàng)建相對應(yīng)的記錄讀取器,負(fù)責(zé)分片中文件的處理。因?yàn)镠adoop中已經(jīng)提供了CombineFileSplit的實(shí)現(xiàn),因此CombineFileSplit無須再設(shè)計(jì)。繼承CombineImageRecordReader類,定義ImageRecordReader實(shí)現(xiàn)對CombineFileSplit分片中單個小文件記錄的讀取。
圖1 海量車牌圖像小文件處理流程
(4)配置MapReduce以實(shí)現(xiàn)對海量車牌圖像的處理。
Hadoop沒有提供專用的圖像接口,因此不能直接處理車牌圖像數(shù)據(jù)。Hadoop的Writable接口定義了一種二進(jìn)制輸入流方法和一種二進(jìn)制輸出流方法,這兩種方法可以實(shí)現(xiàn)數(shù)據(jù)的序列化和反序列化。因此,要處理圖像數(shù)據(jù),需要繼承Writable接口,定義一個圖像類接口Image類,并在Image類中重寫Writable類的readFields和write兩種方法,分別用于寫入和讀出圖像的相關(guān)數(shù)據(jù)信息。經(jīng)過設(shè)計(jì)的Image類圖如圖2所示。
圖2 Image類圖
CFIF作為Mapper的輸入格式,將來自多個小文件的分片打包到一個大的輸入分片中,因此需要從CFIF類繼承一個CombineImageInputFormat類,并在CombineImageInputFormat類中創(chuàng)建CombineImageRecordReader。CombineFileRecordReader是針對CombineFileSplit的通用RecordReader,是為來自不同文件的分片創(chuàng)建相對應(yīng)的記錄讀取器,負(fù)責(zé)分片中文件的處理,即讀取CombineFileSplit中的文件Block并轉(zhuǎn)化為
(1)CombineImageRecordReader類。
從RecordReader繼承一個CombineImageRecordReader類,把CombineFileSplit中的每一個小文件分片轉(zhuǎn)化為
CombineImageRecordReader extends RecordReader
CombineImageRecordReader(CombineFileSplit,split,TaskAttemptContext context,Integer index) {CombineFileSplit ThisSplit=split; //獲取文件分片
//對緩沖區(qū)中的圖像解碼,img用作鍵值對的值
img=new Image(BufferedImage)};
//獲取當(dāng)前輸入文件分片的路徑,用作鍵值對的鍵
filePath=ThisSplit.getPath(index);}}
(2)CombineImageInputFormat類。
繼承CFIF類,定義CombineImageInputFormat作為Mapper的圖像輸入格式,具體代碼如下:
CombineImageInputFormat extends CFIF
//設(shè)置RecordReader為CombineImageRecordReader
RecordReader
return newCombineImageRecordReader
//不對單個圖像文件分片
isSplitable(JobContext context,Path file){return false;}}
在Mapper階段,從CombineImageRecordReader那里得到
在Reducer階段,新key表示輸出路徑,其中圖像文件以“原主文件名(車牌號).jpg”的形式命名,并把image特征圖以新key為路徑保存。
采用偽分布式搭建Hadoop云計(jì)算平臺,該云計(jì)算平臺由一個NameNode節(jié)點(diǎn)和三個DataNode節(jié)點(diǎn)組成。各節(jié)點(diǎn)的配置如表1所示,所需軟件配置如表2所示。
表1 Hadoop集群節(jié)點(diǎn)配置
表2 軟件配置
為了測試CFIF方式在內(nèi)存消耗與運(yùn)行時(shí)間方面的性能,特意設(shè)計(jì)兩組對比實(shí)驗(yàn),準(zhǔn)備6組(1 000,2 000,3 000,4 000,5 000,6 000)車牌圖像文件,在不同方案下,分別通過分布式環(huán)境運(yùn)行每組等量的車牌識別任務(wù)。
(1)測試HDFS(即傳統(tǒng)的單文件單Map任務(wù))、Hadoop Archives(HAR)、MapFile(簡稱MF)及CFIF方案下,處理6組車牌圖像文件的完成時(shí)間。
(2)測試HDFS、HAR、MF和CFIF四種方案下NameNode節(jié)點(diǎn)所占用的內(nèi)存百分比。
兩組實(shí)驗(yàn)的測試結(jié)果分別如圖3、圖4所示。
圖3 完成時(shí)間對比
由圖3可見,在運(yùn)行效率方面,CFIF在四種方案中表現(xiàn)最好,原因在于CFIF方案把小文件分片打包成了大分片,減少了Map任務(wù)的數(shù)量,從而避免了頻繁開啟和關(guān)閉Map所帶來的時(shí)間損耗。MapFile的處理效率稍遜于CFIF,原因是CFIF在將多個小文件的分片打包到一個大分片時(shí),充分考慮了數(shù)據(jù)的本地性原則,即盡量將同一節(jié)點(diǎn)的小文件打包,因此節(jié)省了數(shù)據(jù)在節(jié)點(diǎn)間傳輸所帶來的時(shí)間開銷,而MF方案在合并文件時(shí)沒有考慮這點(diǎn)。HAR與HDFS方案在運(yùn)行效率上相當(dāng),雖然HAR將多個圖像小文件打包作為MapReduce的輸入,但HAR沒有對文件進(jìn)行合并,MapReduce還是給每個圖像小文件各啟動了一個Map任務(wù),這并沒有減少總的Map任務(wù)數(shù),因此HAR并不比HDFS在運(yùn)行效率上有效。
圖4 NameNode內(nèi)存占用率對比
由圖4可見,在NameNode內(nèi)存消耗方面,HAR、MF和CFIF遠(yuǎn)低于HDFS,這是因?yàn)镠DFS集群下每一個小文件均占據(jù)一個Block,海量的小文件會消耗大量NameNode內(nèi)存。從圖中還可以看出,HAR、MF和CFIF的表現(xiàn)不相上下,原因是三者通過對文件打包及合并,減少了元數(shù)據(jù)所占用的NameNode內(nèi)存空間,因此NameNode內(nèi)存消耗不明顯。
文中深入分析了Hadoop存儲及處理海量小文件時(shí)所引發(fā)的性能問題,并對現(xiàn)有的幾種解決方案的缺點(diǎn)進(jìn)行了詳細(xì)的分析。在此基礎(chǔ)上,采用CFIF抽象類將多個小文件分片打包到大分片中,以減少M(fèi)ap任務(wù)的啟動數(shù)量,從而提高處理海量小文件的效率。對CFIF抽象類給出了具體實(shí)現(xiàn),并通過實(shí)驗(yàn)與常規(guī)HDFS、HAR和MF方案在NameNode內(nèi)存空間和運(yùn)行效率方面進(jìn)行了對比。實(shí)驗(yàn)結(jié)果表明,CFIF在NameNode內(nèi)存占用率和運(yùn)行效率方面都有很好的表現(xiàn)。