1. 程式人生 > >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 可以執行多個以上的分割任務.

小檔案怎麼產生的?

這裡至少有兩個場景

  1. 這些檔案是一個更大的邏輯檔案. 由於HDFS最近才支援追加,一個非常通用的儲存無界檔案(例如日誌檔案)的模式是寫在HDFS塊.
  2. 有的檔案一直比較小. 想象一個大的影象庫. 每一個檔案是一個不同的檔案, 沒有自然的方法把它們組合成一個更大的檔案.

這兩者需要不同的解決方案. 對於第一個例項, 檔案是有一個個記錄組成, 這個問題可以通過呼叫 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上的檔案數量並沒有減少.
SequenceFile and MapFile File Layouts

在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 File Layout
不像HAR檔案, SequenceFile檔案沒法羅列出所有的keys,簡短的閱讀需要獲取通過整個檔案. (MapFiles檔案很像一個已經對key進行排序的 SequenceFiles 檔案, 維護部分索引, 所以他們不能羅列所有它們的keys — 如圖所示.)

SequenceFile檔案相當於Java的核心. TFile檔案被設計成跨平臺的, 是一個可以替代的 SequenceFile, 但它尚未提供.

HBase

如果你產生了很多小檔案, 然而, 根據訪問模式, 不同型別的儲存可能更合適. HBase 儲存資料通過MapFiles (索引SequenceFiles), 是一個很好的選擇如果你需要MapReduce流分析同時也需要隨機訪問檢視. 如果延遲是一個問題, 然而這裡有許多其他的選擇 — 看Richard Jones’ 傑出的survey of key-value stores.