1、概述
小文件是指文件size小於HDFS上block大小的文件。這樣的文件會給Hadoop的擴展性和性能帶來嚴重問題。首先,在HDFS中,任何block,文件或者目錄在內存中均以對象的形式存儲,每個對象約占150byte,如果有1000 0000個小文件,每個文件占用一個block,則namenode大約需要2G空間。如果存儲1億個文件,則namenode需要20G空間(見參考資料[1][4][5])。這樣namenode內存容量嚴重制約了集群的擴展。 其次,訪問大量小文件速度遠遠小於訪問幾個大文件。HDFS最初是為流式訪問大文件開發的,如果訪問大量小文件,需要不斷的從一個datanode跳到另一個datanode,嚴重影響性能。最后,處理大量小文件速度遠遠小於處理同等大小的大文件的速度。每一個小文件要占用一個slot,而task啟動將耗費大量時間甚至大部分時間都耗費在啟動task和釋放task上。
本文首先介紹了hadoop自帶的解決小文件問題的方案(以工具的形式提供),包括Hadoop Archive,Sequence file和CombineFileInputFormat;然后介紹了兩篇從系統層面解決HDFS小文件的論文,一篇是中科院計算所2009年發表的,用以解決HDFS上存儲地理信息小文件的方案;另一篇是IBM於2009年發表的,用以解決HDFS上存儲ppt小文件的方案。
2、HDFS文件讀寫流程
在正式介紹HDFS小文件存儲方案之前,我們先介紹一下當前HDFS上文件存取的基本流程。
(1) 讀文件流程
1)client端發送讀文件請求給namenode,如果文件不存在,返回錯誤信息,否則,將該文件對應的block及其所在datanode位置發送給client
2) client收到文件位置信息后,與不同datanode建立socket連接並行獲取數據。
(2) 寫文件流程
1)client端發送寫文件請求,namenode檢查文件是否存在,如果已存在,直接返回錯誤信息,否則,發送給client一些可用datanode節點
2)client將文件分塊,並行存儲到不同節點上datanode上,發送完成后,client同時發送信息給namenode和datanode
3)namenode收到的client信息后,發送確信信息給datanode
4)datanode同時收到namenode和datanode的確認信息后,提交寫操作。
3、Hadoop自帶的解決方案
對於小文件問題,Hadoop本身也提供了幾個解決方案,分別為:Hadoop Archive,Sequence file和CombineFileInputFormat。
(1) Hadoop Archive
Hadoop Archive或者HAR,是一個高效地將小文件放入HDFS塊中的文件存檔工具,它能夠將多個小文件打包成一個HAR文件,這樣在減少namenode內存使用的同時,仍然允許對文件進行透明的訪問。
對某個目錄/foo/bar下的所有小文件存檔成/outputdir/ zoo.har:
hadoop archive -archiveName zoo.har -p /foo/bar /outputdir
當然,也可以指定HAR的大小(使用-Dhar.block.size)。
HAR是在Hadoop file system之上的一個文件系統,因此所有fs shell命令對HAR文件均可用,只不過是文件路徑格式不一樣,HAR的訪問路徑可以是以下兩種格式:
har://scheme-hostname:port/archivepath/fileinarchive
har:///archivepath/fileinarchive(本節點)
可以這樣查看HAR文件存檔中的文件:
hadoop dfs -ls har:///user/zoo/foo.har
輸出:
har:///user/zoo/foo.har/hadoop/dir1
har:///user/zoo/foo.har/hadoop/dir2
使用HAR時需要兩點,第一,對小文件進行存檔后,原文件並不會自動被刪除,需要用戶自己刪除;第二,創建HAR文件的過程實際上是在運行一個mapreduce作業,因而需要有一個hadoop集群運行此命令。
此外,HAR還有一些缺陷:第一,一旦創建,Archives便不可改變。要增加或移除里面的文件,必須重新創建歸檔文件。第二,要歸檔的文件名中不能有空格,否則會拋出異常,可以將空格用其他符號替換(使用-Dhar.space.replacement.enable=true 和-Dhar.space.replacement參數)。
(2) Sequence file
sequence file由一系列的二進制key/value組成,如果為key小文件名,value為文件內容,則可以將大批小文件合並成一個大文件。
Hadoop-0.21.0中提供了SequenceFile,包括Writer,Reader和SequenceFileSorter類進行寫,讀和排序操作。如果hadoop版本低於0.21.0的版本,實現方法可參見[3]。
(3)CombineFileInputFormat
CombineFileInputFormat是一種新的inputformat,用於將多個文件合並成一個單獨的split,另外,它會考慮數據的存儲位置。