MapReduce Shuffle流程

總的MapReduce 過程

Map端Shuffle過程

Map Shuffle
每個map task都有一個內存緩衝區,存儲着map的輸出結果,當緩衝區快滿的時候需要將緩衝區的數據以一個臨時文件的方式存放到磁盤,當整個map task結束後再對磁盤中這個map task產生的所有臨時文件做合併,生成最終的正式輸出文件,然後等待reduce task來拉數據。
執行步驟(4個):

  1. 在map task執行時,它的輸入數據來源於HDFS的block,當然在MapReduce概念中,map task只讀取split。Split與block的對應關係可能是多對一,默認是一對一。在WordCount例子裏,假設map的輸入數據都是像“aaa”這樣的字符串。
  2. 在經過mapper的運行後,我們得知mapper的輸出是這樣一個key/value對: key是“aaa”, value是數值1。因爲當前map端只做加1的操作,在reduce task裏纔去合併結果集。前面我們知道這個job有3個reduce task,到底當前的“aaa”應該交由哪個reduce去做呢,是需要現在決定的。
    MapReduce提供Partitioner接口,它的作用就是根據key或value及reduce的數量來決定當前的這對輸出數據最終應該交由哪個reduce task處理。默認對key hash後再以reduce task數量取模。默認的取模方式只是爲了平均reduce的處理能力,如果用戶自己對Partitioner有需求,可以訂製並設置到job上。
  3. 內存緩衝區是有大小限制的,默認是100MB。當map task的輸出結果很多時,就可能會撐爆內存,所以需要在一定條件下將緩衝區中的數據臨時寫入磁盤,然後重新利用這塊緩衝區。這個從內存往磁盤寫數據的過程被稱爲Spill,中文可譯爲溢寫,字面意思很直觀。這個溢寫是由單獨線程來完成,不影響往緩衝區寫map結果的線程。溢寫線程啓動時不應該阻止map的結果輸出,所以整個緩衝區有個溢寫的比例spill.percent。這個比例默認是0.8,也就是當緩衝區的數據已經達到閾值(buffer size * spill percent = 100MB * 0.8 = 80MB),溢寫線程啓動,鎖定這80MB的內存,執行溢寫過程。Map task的輸出結果還可以往剩下的20MB內存中寫,互不影響。當溢寫線程啓動後,需要對這80MB空間內的key做排序(Sort)。排序是MapReduce模型默認的行爲,這裏的排序也是對序列化的字節做的排序。將有相同key的key/value對的value加起來,減少溢寫到磁盤的數據量。Combiner會優化MapReduce的中間結果,所以它在整個模型中會多次使用。那哪些場景才能使用Combiner呢?從這裏分析,Combiner的輸出是Reducer的輸入,Combiner絕不能改變最終的計算結果。Combiner只應該用於那種Reduce的輸入key/value與輸出key/value類型完全一致,且不影響最終結果的場景。比如累加,最大值等。Combiner的使用一定得慎重,如果用好,它對job執行效率有幫助,反之會影響reduce的最終結果。
  4. 每次溢寫會在磁盤上生成一個溢寫文件,如果map的輸出結果真的很大,有多次這樣的溢寫發生,磁盤上相應的就會有多個溢寫文件存在。當map task真正完成時,內存緩衝區中的數據也全部溢寫到磁盤中形成一個溢寫文件。最終磁盤中會至少有一個這樣的溢寫文件存在(如果map的輸出結果很少,當map執行完成時,只會產生一個溢寫文件),因爲最終的文件只有一個,所以需要將這些溢寫文件歸併到一起,這個過程就叫做Merge。

Reduce端Shuffle執行過程

Reduce ShuffleReducer真正運行之前,所有的時間都是在拉取數據,做merge,且不斷重複地在做。
執行步驟(3個):

  1. Copy過程,簡單地拉取數據。Reduce進程啓動一些數據copy線程(Fetcher),通過HTTP方式請求map task所在的TaskTracker獲取map task的輸出文件。因爲map task早已結束,這些文件就歸TaskTracker管理在本地磁盤中。
  2. Merge階段。這裏的merge如map端的merge動作,只是數組中存放的是不同map端copy來的數值。Copy過來的數據會先放入內存緩衝區中,這裏的緩衝區大小要比map端的更爲靈活,它基於JVM的heap size設置,因爲Shuffle階段Reducer不運行,所以應該把絕大部分的內存都給Shuffle用。這裏需要強調的是,merge有三種形式:1)內存到內存 2)內存到磁盤 3)磁盤到磁盤。默認情況下第一種形式不啓用。當內存中的數據量到達一定閾值,就啓動內存到磁盤的merge。與map 端類似,這也是溢寫的過程,這個過程中如果你設置有Combiner,也是會啓用的,然後在磁盤中生成了衆多的溢寫文件。第二種merge方式一直在運行,直到沒有map端的數據時才結束,然後啓動第三種磁盤到磁盤的merge方式生成最終的那個文件。
  3. Reducer的輸入文件。不斷地merge後,最後會生成一個“最終文件”。爲什麼加引號?因爲這個文件可能存在於磁盤上,也可能存在於內存中。對我們來說,當然希望它存放於內存中,直接作爲Reducer的輸入,但默認情況下,這個文件是存放於磁盤中的。當Reducer的輸入文件已定,整個Shuffle才最終結束。然後就是Reducer執行,把結果放到HDFS上。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章