Apache Hadoop最佳實踐和反模式

來源: 51CTO  發布時間: 2010-12-06 10:21  閱讀: 2077 次  推薦: 0   原文鏈接   [收藏]  
摘要:本文介紹了在Apache Hadoop上運行應用程序的最佳實踐,實際上,我們引入了網格模式(Grid Pattern)的概念,它和設計模式類似,它代表運行在網格(Grid)上的應用程序的可復用解決方案。

  Apache Hadoop是一個用于構建大規模,共享存儲和計算基礎設施的軟件框架,Hadoop集群經常用于各種研究和開發項目,如Yahoo!,eBay,Facebook,Twitter等互聯網公司就大量使用了Hadoop,并在核心業務系統中扮演中關鍵角色,因此正確部署Hadoop集群是確保獲得最佳投資回報的關鍵。

  本文介紹了在Apache Hadoop上運行應用程序的最佳實踐,實際上,我們引入了網格模式(Grid Pattern)的概念,它和設計模式類似,它代表運行在網格(Grid)上的應用程序的可復用解決方案。

  概述

  Hadoop上的應用程序數據是使用Map-Reduce(映射-化簡)范式寫入的,Map-Reduce作業通常要將輸入數據集拆分成獨立的數據塊,由Map任務以完全并行的方式處理,框架對Map的輸出結果排序,然后傳遞給Reduce任務,通常情況下,作業的輸入和輸出結果都保存在文件系統上,框架管理計劃任務,監控它們的執行情況,以及重新執行失敗的任務。

  Map-Reduce應用程序指定輸入/輸出位置,通過實現適當的Hadoop接口,如Mapper和Reducer,分別提供Map和Reduce功能,它們和其它作業參數一起構成作業配置。Hadoop作業客戶端將作業(jar/可執行文件等)和配置提交給JobTracker,JobTracker承擔起分配軟件/配置,調度任務和監控的職責,為作業客戶端提供狀態和診斷信息。

  Map/Reduce框架工作在(鍵/值)對上,也就是說,框架將給作業的輸入看作是一對,并產生一對作為作業的輸出,當然輸入輸出的類型可能是不同的。

下面是Map/Reduce應用程序中常見的數據流:

Map/Reduce應用程序中的數據流 
圖1: Map/Reduce應用程序中的數據流

  絕大多數Map-Reduce應用程序都在網格上執行,不會直接實現低級的Map-Reduce接口,相反,它們使用高級語言,如Pig實現。

  Oozie是網格上完美的工作流管理和調度解決方案,它支持多種接口(Hadoop Map-Reduce,Pig,Hadoop Streaming和Hadoop Pipes等),并可以根據時間或數據可用性實現應用程序的調度。

  網格模式

  這部分內容涉及在網格上運行Map-Reduce應用程序的最佳實踐。

  輸入

  Hadoop Map-Reduce專門為處理大批量數據做了優化,Map通常使用并行方式處理數據,至少1個HDFS數據塊,也就是說每次最少要處理128MB的數據。

  ◆默認情況下,這個框架每個Map至少要處理1個HDFS文件,這意味著如果某個應用程序要處理非常大的輸入文件,最好是通過一種特殊的輸入格式,如MultiFileInputFormat,讓每個Map處理多個文件,即便是在處理為數不多的小型輸入文件時也理應如此,每個Map處理多個文件可以大大提高效率。

  ◆如果應用程序需要處理大量的數據,即使它們存在于大型文件中,每個Map處理超過128MB的數據也會更快。
  網格模式:在少量Map中聚合處理多個小型輸入文件,使用更大的HDFS塊大小處理超大型數據集。

  Map(映射)

  Map的數量通常是由輸入的總大小決定的,即所有輸入文件的總數據塊數,因此,如果你要處理10TB輸入數據,塊大小128MB,那么總共需要82000個Map。

  任務設置需要一段時間,因此執行大型作業時,Map至少需要一分鐘。正如前面提到的,讓每個Map同時處理多個文件效率會更高,因此,如果應用程序要處理超大型輸入文件,讓每個Map處理更大的數據塊更有效,例如,讓每個Map處理更多數據的一個方法是讓應用程序處理更大的HDFS數據塊,如512MB或盡可能更大。

  作為一個極端的例子,Map-Reduce開發團隊使用大約66000個Map完成了PB級數據的排序(PetaSort),也就是說,66000個Map處理了1PB數據(每個Map負責12.5GB)。但太多的Map在很短的時間內同時運行很容易造成反效果。

  網格模式:除非應用程序的Map有嚴重的CPU限制,單個應用程序幾乎沒有任何理由需要超過60000-7000個Map。同樣,當Map處理更大的數據塊時,重要的是確保它們有足夠的內存,以便排序緩沖區加速Map端排序(請閱讀參考文檔的io.sort.mb和io.sort.record.percent小節),如果Map輸出可以直接在Map的排序緩沖區中處理,應用程序的性能可以大大提高,Map JVM必須承擔更大的堆大小,重要的是要記住內存中去除序列化的輸入大小和在磁盤上的大小可能有很大的不同,在這種情況下,應用程序需要更大的堆大小確保Map輸入記錄和Map輸出記錄可以保持在內存中。

  網格模式:確保Map大小合適,以便所有Map輸出可以保持在排序緩沖區中。

  Map數量合適對應用程序有以下這些好處:

  ◆減少調度開銷,更少的Map意味著任務調度也更簡單,集群的可用性也更高;

  ◆Map端更高效,因為有足夠的內存容納Map輸出;

  ◆減少了從Map向Reduce清洗Map輸出需要的查找次數,記住每個Map為每個Reduce產生輸出,因此查找次數等m*r,m表示Map數量,r表示Reduce數量。

  ◆每個清洗的片段更大,減少了建立連接的開銷;

  ◆Reduce端合并了排序后的Map輸出,效率更高,因為需要合并的Map輸出片段更少了。

  值得注意的是,每個Map處理太多的數據可能并不完全是好事,至少對故障恢復來說會很麻煩,即使是單點Map故障,也會造成嚴重的應用程序延遲。

  網格模式:應用程序應使用較少的Map并行處理數據,確保不會出現糟糕的故障恢復情況。

  合并器(Combiner)

  合理使用合并器,應用程序可以獲得更好的聚合效果,合并器最大的優勢在于可以大大減少從Map到Reduce清洗的數據量。

  清洗(Shuffle)

  雖然使用合并器會得到更好的聚合效果,但它存在性能問題,因為它需要承擔起額外的Map輸出記錄序列化/反序列化任務,應用程序可以使用合并器輸入/輸出記錄計數器測量合并器的效率。

  網格模式:合并器可以幫助應用程序減少清洗階段的網絡流量,但最重要的是要確保合并器要提供足夠的聚合能力。

  Reduce(化簡)

  Reduce的效率很大程度上是由清洗的性能決定的,應用程序配置的Reduce數量也很關鍵,太多或過少的Reduce都會產生反效果。

  ◆太少的Reduce會給節點造成負載過重,我曾看到最極端的情況,每個Reduce負責處理超過100GB的數據,同樣,也會使故障恢復變得很困難,因為即便是單個Reduce故障也會引起顯著的作業延遲。

  ◆太多的Reduce會給清洗閂帶來不利影響,同樣,在極端情況下,它會創建太多的小文件作為作業的輸出,這會影響到應用程序以后處理小文件性能。
  網格模式:應用程序應該確保每個Reduce最少可以處理1-2GB數據,最多5-10GB數據。

  輸出

  一個關鍵因素是要記住應用程序的輸出數量是和配置的Reduce數量呈線性關系的,正如前面提到的,配置數量適當的Reduce是非常重要的。此外,還需要考慮一些其它因素:

  ◆使用壓縮程序對應用程序的輸出做適當的壓縮,提高HDFS寫入性能;

  ◆每個Reduce不止輸出一個輸出文件,可以避免使用側文件(side-file),應用程序通常會寫一些側文件來捕捉統計數據,如果所收集的統計數據很小,計數器可能更合適;

  ◆為Reduce輸出使用合適的文件格式,對下游用戶來說,使用zlib/gzip/lzo等編碼器輸出大量的文本壓縮數據會適得其反,因為這些格式的文件無法再拆分,Map-Reduce框架必須強制單個Map處理整個文件,這會使負載均衡變得非常糟糕,并導致故障恢復變得很困難。應該使用SequenceFile和TFile格式緩解這些問題,因為它們既是可壓縮的,又是可以再拆分的。

  ◆當獨立輸出文件很大時(數GB),最好使用更大的輸出塊大小(dfs.block.size)。

  網格模式:應用程序輸出少量的大文件,每個文件橫跨多個HDFS塊,并經過適當的壓縮。

  分布式緩存(DistributedCache)

  分布式緩存高效分發應用程序相關的大型只讀文件,它是Map-Reduce框架為應用程序緩存文件(文本,壓縮文件,jar等)提供的一種手段,任何任務在從屬節點上執行之前,Map-Reduce框架將會把必要的文件拷貝到從屬節點上,其高效源于這些文件只會被復制一次,并提供從屬節點上未壓縮文件的緩存能力,它可以在Map或Reduce任務中作為一個最基本的軟件分發機制,用于分發jar和本地庫文件,只需要設定classpath或本地庫路徑即可。

  分布式緩存被設計為主要用于分發少量中等規模的文件,大小從幾MB到幾十MB,分布式緩存當前實現的一個缺點是無法指定Map或Reduce的相關的產物(文件)。
  在極少數情況下,由任務本身復制這些產物可能更恰當,例如,如果應用程序只配有少量Reduce,但需要分布式緩存中非常大型的產物(如大于512MB)。

  網格模式:應用程序應該確保分布式緩存中的產物不能要求過多的I/O,不能多于應用程序任務真實的輸入。

  計數器(Counters)

  這里指的是全局計數器,由Map/Reduce框架或應用程序定義,應用程序可以定義任意的計數器,然后在Map和/或Reduce方法中更新,這些計數器再通過框架進行全局匯總。

  計數器應以跟蹤少量的,重要的全局信息為妥,它們絕不是為了聚合非常細粒度的應用程序統計數據。

  計數器代價非常高,因為JobTracker必須在整個應用程序生命周期維護每個Map/Reduce任務的計數器。

  網格模式:應用程序不應該使用超過10,15或25個自定義計數器。

  壓縮

  Hadoop Map-Reduce為應用程序中間Map輸出和應用程序輸出結果提供壓縮,也就是說可以減少輸出結果大小。

  中間輸出壓縮:正如前面講到的,采用適當的壓縮編碼對中間Map輸出結果進行壓縮,可以減少Map和Reduce之間的網絡流量,從而提高性能,Lzo是壓縮Map輸出結果的理想選擇,因為它在高CPU效率下提供了很好的壓縮比。

  應用程序輸出壓縮:采用適當的壓縮編碼和文件格式對應用程序輸出結果進行壓縮,可以提供更好的應用程序延遲,在大多數情況下,Zlib/Gzip可能是較好的選擇,因為它們在合理的速度下提供了高壓縮率,bzip2通常用于對壓縮速度要求不要的情景。

  全序輸出(抽樣)

  有時應用程序需要產生全序輸出,也就是說輸出結果要全部排好序,在這種情況下,應用程序常用的一個反模式是使用單個Reduce,強制單一的全局聚合,很明顯,這樣做是非常低效的,不僅使Reduce任務所在的單個節點上的負載很重,也使故障恢復變得很困難。

  更好的辦法是對輸入抽樣,用抽樣結果驅動采樣分區程序,而不是默認的散列分區程序,這樣才可以提供更好的負載均衡和故障恢復能力。

  連接全序數據集

  在網格上需要注意的另一個要素是連接兩個全序數據集,注意,它們和基數可能不是精確的倍數關系,例如,一個數據集有512個 Bucket,而其它數據集只有200個Bucket。

  在這種情況下,確保輸入數據是全序的,這樣應用程序就可以使用數據集的基數,Pig以高效的方式處理這些連接。

  HDFS操作&JobTracker操作

  NameNode是一個寶貴的資源,在網格中執行HDFS操作時,應用程序需要謹慎,特別是,我們不鼓勵應用程序做非I/O操作,即Map/Reduce任務中的元數據操作,如遞歸統計,統計大型目錄等。

  同樣,應用程序不應該為集群統計從后端聯系JobTracker。

  網格模式:應用程序不應該從后端在文件系統上執行任何元數據操作,他們應限制到作業提交期間的作業客戶端,此外,應用程序不應該從后端聯系JobTracker。
  用戶日志

  用戶任務日志,即Map/Reduce任務的srdout和stderr,存儲在任務執行所在計算節點的本地磁盤上。

  由于節點是共享基礎設施的一部分,Map/Reduce框架限制了存儲在節點上的任務日志數量。

  Web用戶界面

  Hadoop Map/Reduce框架提供了一個基本的Web用戶界面通過JobTracker跟蹤運行中的作業,它們的進度和已完成作業歷史等。

  最重要的是要記住Web用戶界面是提供給人使用的,而不是為自動化過程提供的。

  實現自動化過程抓取Web用戶界面是被嚴格禁止的,Web用戶界面中的某些部件,如瀏覽作業歷史,在JobTracker上是非常耗資源的,可能會導致嚴重的性能問題。
  如果確實需要自動統計收集數據,最好咨詢網格解決方案提供商,網格SE,或Map-Reduce開發團隊。

  工作流

  Oozie是網格首選的工作流管理和調度系統,它可以基于時間或數據可用性管理工作流和提供調度方案,漸漸地,延遲敏感的生產作業管線也通過Oozie進行管理和調度。

  設計Oozie工作流時需要牢記的一點是,Hadoop更適合批處理超大型數據,同樣,從處理角度來看,工作流最好是由少量中到大型Map-Reduce作業組成,而不是由大量的小型Map-Reduce作業組成,作為一個極端的例子,我們曾看到過一個工作流由數千個作業組成的情景,這是一個很明顯的反模式,就目前而言,Hadoop框架并不真正適合這種性質的業務,最好是將這些數以千計的Map-Reduce作業減少到合適的數量,這將有助于提高工作流性能,減少延遲。

  網格模式:工作流中的單個Map-Reduce作業至少應該處理幾十GB數據。

  反模式

  這一部分介紹一些在網格上運行的應用程序常見的反模式,通常它們不符合大規模,分布式,批量數據處理系統的精神。應用程序開發人員需要引起注意,因為網格軟件堆棧正變得硬化,特別是即將發布的20.Fred,一些常見的反模式如下:

  ◆應用程序不使用如Pig等高級接口,除非確有必要。

  ◆處理成千上萬的小文件(大小小于1 HDFS塊,通常是128MB),使用一個Map處理單個小文件。

  ◆使用小的HDFS塊大小(即128MB)處理非常大的數據集,導致需要數以萬計的Map。

  ◆有大量Map(數千)的應用程序運行時很短(如5s)。

  ◆不使用合并器進行直接聚合。

  ◆應用程序Map數大于60000-70000個。

  ◆應用程序用很少的Reduce(如1個)處理大型數據集。

  ◆Pig腳本未用PARALLEL關鍵字處理大型數據集。

  ◆應用程序使用單個Reduce為輸出記錄實現全排序。

  ◆應用程序使用大量的Reduce處理數據,每個Reduce處理不到1-2GB數據。

  ◆應用程序為每個Reduce輸出多個小型輸出文件。

  ◆應用程序使用分布式緩存分發大量產物和/或非常大的產物(每一個數千MB)。

  ◆應用程序為每個任務使用數十個或數千個計數器。

  ◆應用程序從Map/Reduce任務在文件系統上執行元數據操作(如listStatus)。

  ◆應用程序為隊列/作業的狀態抓取JobTracker Web用戶界面,或更糟的是已完成作業的歷史。

  ◆工作流由數千個處理少量數據的小型作業組成。

0
0
 
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()