Hadoop之MapReduce工作原理

    Hadoop由兩部分組成,分別是分佈式文件系統HDFS和分佈式計算框架MapReduce。其中,分佈式文件系統HDFS主要用於大規模數據的分佈式存儲,而MapReduce則構建在分佈式文件系統上,對於存儲在分佈式文件系統的數據進行分佈式計算。

1  MapReduce設計目標

    HadoopMapReduce誕生於搜索領域,主要解決搜索引擎面臨的海量數據處理擴展性差的問題。它的實現很大程度上借鑑了Google MapReduce的設計思想,包括簡化編程接口、提高系統容錯性等。總結HadoopMapReduce設計目標,主要有以下幾個:

1、易於編程:傳統的分佈式程序設計非常複雜,用戶需要關注的細節非常多,比如數據分片、數據傳輸、節點間通信等。因而設計分佈式程序的門檻非常高。Hadoop的一個重要設計目標是簡化分佈式程序設計,將所有並行程序均需要關注的設計細節抽象成公共模塊並交由系統實現,而用戶只需專注於自己的應用程序邏輯實現,這樣簡化了分佈式程序設計且提高了開發效率。

2、良好的擴展性:隨着公司業務的發展,積累的數據量會越來越大,當數據量增加到一定程度後,現有的集羣可能已經無法滿足其計算能力和存儲能力,這時候管理員可能期望通過添加機器以達到線性擴展集羣能力的目的。

3、高容錯性:在分佈式環境下。隨着集羣規模的增加,集羣中的故障率(這裏的故障包括磁盤損壞、機器宕機、節點間通訊失敗等硬件故障和壞數據或者用戶程序bug產生的軟件故障)會顯著增加,進而導致任務失敗和數據丟失的可能性增加,爲此,Hadoop通過計算遷移或者數據遷移等策略提高集羣的可用性與容錯性。

 

2  MapReduce原理

2.1  MapReduce編程模型

    MapReduce採用"分而治之"的思想,把對大規模數據集的操作,分發給一個主節點管理下的各個分節點共同完成,然後通過整合各個節點的中間結果,得到最終結果。簡單地說,MapReduce就是"任務的分解與結果的彙總"。

在Hadoop中,用於執行MapReduce任務的機器角色有兩個:一個是JobTracker;另一個是TaskTracker,JobTracker是用於調度工作的,TaskTracker是用於執行工作的。一個Hadoop集羣中只有一臺JobTracker。

在分佈式計算中,MapReduce框架負責處理了並行編程中分佈式存儲、工作調度、負載均衡、容錯均衡、容錯處理以及網絡通信等複雜問題,把處理過程高度抽象爲兩個函數:map和reduce,map負責把任務分解成多個任務,reduce負責把分解後多任務處理的結果彙總起來。

需要注意的是,用MapReduce來處理的數據集(或任務)必須具備這樣的特點:待處理的數據集可以分解成許多小的數據集,而且每一個小數據集都可以完全並行地進行處理。

2.2  Hadoop MapReduce架構

同HDFS一樣,Hadoop MapReduce也採用了Master/Slaves(M/S)架構,如下圖所示,它主要由以下幾個組件組成:Client、JobTracker、TaskTracker和Task。

wKioL1fADCCjnLoJAADE82DkSI8013.png-wh_50

    下面分別對這幾個組件進行介紹:

    A、Client

    用戶編寫的MapReduce程序通過Client提交到JobTracker端。同時。用戶可以通過Client提供的一些接口查看作業運行狀態。在Hadoop內部用“作業”(Job)表示MapReduce程序。一個MapReduce程序可以對應若干個作業,而每個作業被分解成若干個Map/Reduce任務(Task)。

    B、JobTracker

    JobTracker主要負責資源監控和作業調度。JobTracker監控所有TaskTracker與作業的健康狀況,一旦發現失敗情況後,其會將相應的任務轉移到其它節點。同時,JobTracker會跟蹤任務的執行進度、資源使用量等信息,並將這些信息告訴任務調度器,而調度器會在資源出現空閒時,選擇合適的任務使用這些資源。在Hadoop中,任務調度器是一個可插拔的模塊,用戶可以根據自己的需要設計相應的調度器。

    C、TaskTracker

    TaskTracker會週期性地通過Heartbeat將本節點上資源的使用情況和任務的運行進度彙報給JobTracker,同時接收JobTracker發送過來的命令並執行相應的操作(例如啓動新任務、殺死任務等)。

    TaskTracker使用“slot”等量劃分本節點的數量,“slot”代表計算資源(CPU、內存等)。

    一個Task獲取到一個slot後纔有機會運行,而Hadoop調度器的作用就是將各個TaskTracker上的空閒slot分配給Task使用。

    Slot分爲Map slot和Reduce slot兩種,分別提供Map Task和Reduce Task。TaskTracker通過slot數目限定Task的併發度。

    D、Task

    Task分爲Map Task和Reduce Task兩種,均有TaskTracker啓動。我們知道,HDFS以固定大小的block爲基本單位存儲數據,而對於MapReduce而言,其處理基本單位是分片(split).

    split是一個邏輯概念,它只包含一些元數據信息,比如數據起始位置、數據長度、數據所在節點等等。它的劃分方法完全由用戶自己決定,但是建議split的劃分大小與HDFS的block大小一致。

    需要注意的是,split的多少決定Map Task的數目,因爲每個split會交由一個Map Task處理。


    Split與blcok的對應關係圖:

wKiom1fADDGgKVKvAAHYDlS0mIc485.jpg-wh_50

    MapTask先將對應的split迭代解析成一個個key/value對,依次調用用戶自定義的map函數進行處理,最終將臨時結果存放到本地磁盤上,其中臨時數據被分成若干個partition,每個partition將被一個ReduceTask處理。

    ReduceTask分爲三個階段:第一步,從遠程節點上讀取Map Task中間結果,稱爲Shuffle階段。第二步,按照key對key/value進行排序,稱爲Sort階段。第三步,依次讀取<key,value list>,調用用戶自定義的reduce函數處理,並將最終結果存到HDFS上,稱爲Reduce階段。

2.3  Hadoop MapReduce作業的生命週期

    這段主要講解Map Reduce的物理實體作業的生命週期,即從作業提交到運行結束的整個過程。如下圖所示:

wKiom1fADFHCZ-igAAFuYAeFdr0171.png-wh_50

步驟 1 作業提交與初始化。用戶提交作業後,首先由 JobClient 實例將作業相關信息,比如將程序 jar 包、作業配置文件、分片元信息文件等上傳到分佈式文件系統(一般爲HDFS)上,其中,分片元信息文件記錄了每個輸入分片的邏輯位置信息。然後JobClient 通過 RPC通知JobTracker。JobTracker收到新作業提交請求後,由作業調度模塊對作業進 行初始化 :爲作業創建一個JobInProgress對象以跟蹤作業運行狀況,而 JobInProgress 則會爲每個Task創建一個TaskInProgress 對象以跟蹤每個任務的運行狀態,TaskInProgress 可能需要管理多個“Task 運行嘗試”(稱爲“Task Attempt”)。

 

步驟 2 任務調度與監控。前面提到,任務調度和監控的功能均由JobTracker 完成。 TaskTracker 週期性地通過Heartbeat向JobTracker彙報本節點的資源使用情況,一旦出現空閒資源,JobTracker會按照一定的策略選擇一個合適的任務使用該空閒資源,這由任務調 度器完成。任務調度器是一個可插拔的獨立模塊,且爲雙層架構,即首先選擇作業,然後從該作業中選擇任務,其中,選擇任務時需要重點考慮數據本地性。此外,JobTracker跟蹤作業的整個運行過程,併爲作業的成功運行提供全方位的保障。首先,當TaskTracker或者Task失敗時,轉移計算任務 ;其次,當某個Task執行進度遠落後於同一作業的其他 Task 時, 爲之啓動一個相同 Task,並選取計算快的Task結果作爲最終結果。

 

步驟 3  任務運行環境準備。運行環境準備包括JVM啓動和資源隔離,均由TaskTracker 實現。TaskTracker爲每個Task啓動一個獨立的JVM 以避免不同Task在運行過程中相互影響;同時,TaskTracker使用了操作系統進程實現資源隔離以防止Task濫用資源。

 

步驟 4 任務執行。TaskTracker 爲 Task 準備好運行環境後,便會啓動Task。在運行過 程中,每個 Task 的最新進度首先由 Task 通過 RPC 彙報給TaskTracker,再由 TaskTracker 彙報給JobTracker。

 

步驟 5 作業完成。待所有 Task 執行完畢後,整個作業執行成功。

 

2.4  Hadoop MapReduce作業的運行機制

    這些按照時間順序包括:輸入分片(input split)、map階段、combiner階段、shuffle階段和reduce階段。

    1)  輸入分片(input split):在進行map計算之前,mapreduce會根據輸入文件計算輸入分片(input split),每個輸入分片(input split)針對一個map任務,輸入分片(input split)存儲的並非數據本身,而是一個分片長度和一個記錄數據的位置的數組,輸入分片(input split)往往和hdfs的block(塊)關係很密切,假如我們設定hdfs的塊的大小是64mb,如果我們輸入有三個文件,大小分別是3mb、65mb和127mb,那麼mapreduce會把3mb文件分爲一個輸入分片(input split),65mb則是兩個輸入分片(input split)而127mb也是兩個輸入分片(input split),換句話說我們如果在map計算前做輸入分片調整,例如合併小文件,那麼就會有5個map任務將執行,而且每個map執行的數據大小不均,這個也是mapreduce優化計算的一個關鍵點。

    2)  map階段:就是程序員編寫好的map函數了,因此map函數效率相對好控制,而且一般map操作都是本地化操作也就是在數據存儲節點上進行;

    3)  combiner階段:combiner階段是程序員可以選擇的,combiner其實也是一種reduce操作,因此我們看見WordCount類裏是用reduce進行加載的。Combiner是一個本地化的reduce操作,它是map運算的後續操作,主要是在map計算出中間文件前做一個簡單的合併重複key值的操作,例如我們對文件裏的單詞頻率做統計,map計算時候如果碰到一個hadoop的單詞就會記錄爲1,但是這篇文章裏hadoop可能會出現n多次,那麼map輸出文件冗餘就會很多,因此在reduce計算前對相同的key做一個合併操作,那麼文件會變小,這樣就提高了寬帶的傳輸效率,畢竟hadoop計算力寬帶資源往往是計算的瓶頸也是最爲寶貴的資源,但是combiner操作是有風險的,使用它的原則是combiner的輸入不會影響到reduce計算的最終輸入,例如:如果計算只是求總數,最大值,最小值可以使用combiner,但是做平均值計算使用combiner的話,最終的reduce計算結果就會出錯。

    4)  shuffle階段:將map的輸出作爲reduce的輸入的過程就是shuffle了,這個是mapreduce優化的重點地方。這裏我不講怎麼優化shuffle階段,講講shuffle階段的原理,因爲大部分的書籍裏都沒講清楚shuffle階段。Shuffle一開始就是map階段做輸出操作,一般mapreduce計算的都是海量數據,map輸出時候不可能把所有文件都放到內存操作,因此map寫入磁盤的過程十分的複雜,更何況map輸出時候要對結果進行排序,內存開銷是很大的,map在做輸出時候會在內存裏開啓一個環形內存緩衝區,這個緩衝區專門用來輸出的,默認大小是100mb,並且在配置文件裏爲這個緩衝區設定了一個閥值,默認是0.80(這個大小和閥值都是可以在配置文件裏進行配置的),同時map還會爲輸出操作啓動一個守護線程,如果緩衝區的內存達到了閥值的80%時候,這個守護線程就會把內容寫到磁盤上,這個過程叫spill,另外的20%內存可以繼續寫入要寫進磁盤的數據,寫入磁盤和寫入內存操作是互不干擾的,如果緩存區被撐滿了,那麼map就會阻塞寫入內存的操作,讓寫入磁盤操作完成後再繼續執行寫入內存操作,前面我講到寫入磁盤前會有個排序操作,這個是在寫入磁盤操作時候進行,不是在寫入內存時候進行的,如果我們定義了combiner函數,那麼排序前還會執行combiner操作。每次spill操作也就是寫入磁盤操作時候就會寫一個溢出文件,也就是說在做map輸出有幾次spill就會產生多少個溢出文件,等map輸出全部做完後,map會合並這些輸出文件。這個過程裏還會有一個Partitioner操作,對於這個操作很多人都很迷糊,其實Partitioner操作和map階段的輸入分片(Input split)很像,一個Partitioner對應一個reduce作業,如果我們mapreduce操作只有一個reduce操作,那麼Partitioner就只有一個,如果我們有多個reduce操作,那麼Partitioner對應的就會有多個,Partitioner因此就是reduce的輸入分片,這個程序員可以編程控制,主要是根據實際key和value的值,根據實際業務類型或者爲了更好的reduce負載均衡要求進行,這是提高reduce效率的一個關鍵所在。到了reduce階段就是合併map輸出文件了,Partitioner會找到對應的map輸出文件,然後進行復制操作,複製操作時reduce會開啓幾個複製線程,這些線程默認個數是5個,程序員也可以在配置文件更改複製線程的個數,這個複製過程和map寫入磁盤過程類似,也有閥值和內存大小,閥值一樣可以在配置文件裏配置,而內存大小是直接使用reduce的tasktracker的內存大小,複製時候reduce還會進行排序操作和合並文件操作,這些操作完了就會進行reduce計算了。

    5)  reduce階段:和map函數一樣也是程序員編寫的,最終結果是存儲在hdfs上的。

    如圖所示:

wKiom1fADMKQ1TfkAAKiYZaN8_c589.jpg-wh_50

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章