Hadoop上小文件存儲處理
Hadoop–小文件存儲處理
本篇文章項目是Cloudera論壇中無意中看到的,雖然原文寫於2009年,但是當前開來Hadoop的小文件存儲方案並沒有很好的解決方案,所以感覺作者寫的很好,也很詳細,於是就抽空翻譯了。本次翻譯主要針對對Hadoop感興趣和工作中使用到Hadoop的開發人員提供有價值的中文資料,希望能夠對大家的工作和學習有所幫助。
由於我英語水平有限,部分翻譯雖能了解其大意,但是卻沒法很好的表達出來,所以有些地方翻譯的不是很好。同時也由於能力見識有限,翻譯過程中難免出現個人的主觀或者客觀原因導致與原文檔有差異。在此,我還是建議有能力的童鞋能夠自己去原文看看,同時如果大家發現更好的關於Hadoop小文件處理的文件,也建議大家提出來與大家一同分享。
小文件問題
在Hadoop中小文件是一個大問題 — 或者說, 至少, 他們在用戶的討論區域是比較熱門的話題. 在這篇文章中我將直麵這個問題, 並提出一些常見的解決方案.
在HDFS中的小文件問題
這裏討論的小文件指的是那些在HDFS中小於HDFS塊大小(默認是64M)的文件. 如果你存儲了很多這種小文件, 或者你有很多這種小文件 (如果你並沒有使用Hadoop), 這裏討論的問題是Hadoop不能處理大量的這種文件.
每一個文件, 目錄和塊在HDFS中代表一個對象存儲在namenode的內存中, 它們每一個占用150 字節, 根據經驗. 所以1000萬個文件,每一個使用一個塊, 將大約需要3GB的內存. 遠遠超過當前的硬件處理水平. 當然10億個文件直接沒法處理.
此外, HDFS是沒有能力去有效地訪問小文件:它主要是專為串行流式訪問的大文件設計的. 閱讀小文件通常會導致從一個DataNode到DataNode檢索每個小文件, 所有的這些訪問數據效率都是很低下的.
在MapReduce中小文件問題
Map任務每次能處理一個塊的輸入 (使用的是默認的 FileInputFormat
). 如果文件非常小而且還很多, 導致每次Map任務產生非常小的輸入, 同時這裏需要大量的map任務, 這樣增加了很多額外的開銷. 比較一個1GB 文件分成16 64MB 塊, 10,000 或者 100KB 文件. 10,000文件每個文件使用一個map任務, 這個任務比一個相等的大文件要慢10或者上百倍.
這裏有一些特征能夠減輕額外的開銷:多個任務使用一個JVM, 從而避免了一些JVM啟動開銷 (看mapred.job.reuse.jvm.num.tasks
屬性), 和MultiFileInputSplit
可以運行多個以上的分割任務.
小文件怎麼產生的?
這裏至少有兩個場景
- 這些文件是一個更大的邏輯文件. 由於HDFS最近才支持追加,一個非常通用的保存無界文件(例如日誌文件)的模式是寫在HDFS塊.
- 有的文件一直比較小. 想象一個大的圖像庫. 每一個文件是一個不同的文件, 沒有自然的方法把它們組合成一個更大的文件.
這兩者需要不同的解決方案. 對於第一個實例, 文件是有一個個記錄組成, 這個問題可以通過調用 HDFS’s sync()
方法來避免 (這個是追加, 深入了解可以看 this discussion) 每一個如此頻繁地寫大文件. 另外,你可以通過寫一個程序來把小文件連接在一起 (查看 Nathan Marz’s post 工具能夠實現這種功能).
對於第二種情況,通過一些方式來對文件進行分組操作. Hadoop提供了幾種方案.
HAR files
Hadoop Archives (HAR 文件)被引入到HDFS在0.18.0版本中為了減輕存放許多文件在namenode內存中的問題. HAR 文件的工作原理是在HDFS中建立一個分層的文件係統. 一個 HAR文件創建通過使用hadoop archive
命令,他通過運行一個MapReduce任務把HDFS中的小文件進行打包. 對於客戶端使用HAR文件係統沒有改變: 所有的原始文件是可見的和可訪問的 (通過使用 har:// URL). 然而, 在HDFS上的文件數量並沒有減少.
在HDFS上讀文件比HAR上麵效率要高一些, 事實上,可能會比較慢因為每個HAR文件訪問需要兩個索引文件的讀取以及數據文件的讀取(見下圖). 雖然HAR文件能夠作為MapReduce的輸入文件 , HAR並沒有準許在進行Map操作的時候把所有的文件當著一個塊來操作. 它應該是提供一個輸入的格式能夠在HARs提升改進的地方, 實際上它並沒有. 請注意 MultiFileInputSplit, 即使在 HADOOP-4565 通過選擇本地文件分割來提高, 將也需要查詢每一個小的文件. 通過與SequenceFile文件性能比較是很有趣的, 所以說.現在HARs最常使用的是來處理文檔.
Sequence Files
通常回答關於“小文件問題” 是: 使用SequenceFile. SequenceFile文件的設計思想是使用文件名作為key文件內容作為值. 這在實踐中很好. 回到10,000 100KB 文件問題, 你可以寫一個程序把他們放到一個單獨的SequenceFile文件裏麵, 並且你可以通過串流的形勢對其進行訪問(直接或者通過MapReduce) 在SequenceFile文件上進行操作. 更神奇的地方是. SequenceFiles文件能夠被可拆分, 所以MapReduce可以打破成塊,每一塊獨立操作. 它們也支持壓縮, 不像HARs. 塊壓縮是大多數情況下最好的選擇, 由於壓縮了幾個記錄塊(相當於每個記錄).
它可以將現有的數據轉化成為SequenceFiles. 然而,完全有可能在並行創建一係列sequencefiles. (Stuart Sierra 已經寫了一篇很有用的關於 post 轉換tar文件到SequenceFile文件 — 這種工具是很有益的, 看到更多的人會很好).最好的設計在寫入數據的時候直接寫入到SequenceFiles文件裏麵, 如果可能,而不是寫小文件作為中間步驟.
不像HAR文件, SequenceFile文件沒法羅列出所有的keys,簡短的閱讀需要獲取通過整個文件. (MapFiles文件很像一個已經對key進行排序的 SequenceFiles 文件, 維護部分索引, 所以他們不能羅列所有它們的keys — 如圖所示.)
SequenceFile文件相當於Java的核心. TFile文件被設計成跨平台的, 是一個可以替代的 SequenceFile, 但它尚未提供.
HBase
如果你產生了很多小文件, 然而, 根據訪問模式, 不同類型的存儲可能更合適. HBase 存儲數據通過MapFiles (索引SequenceFiles), 是一個很好的選擇如果你需要MapReduce流分析同時也需要隨機訪問查看. 如果延遲是一個問題, 然而這裏有許多其他的選擇 — 看Richard Jones’ 傑出的survey of key-value stores.
最後更新:2017-05-19 16:37:58