MapReduce 基礎 (六)MapReduce的運行機制

1. MapTask 工作機制

image
image

整個Map階段流程大體如上圖所示。

簡單概述:inputFile通過split被邏輯切分為多個split文件,通過Record按行讀取內容給 map(用戶自己實現的)進行處理,數據被map處理結束之后交給OutputCollector收集器,對 其結果key進行分區(默認使用hash分區),然后寫入buwer,每個map task都有一個內存緩沖 區,存儲著map的輸出結果,當緩沖區快滿的時候需要將緩沖區的數據以一個臨時文件的方 式存放到磁盤,當整個map task結束后再對磁盤中這個map task產生的所有臨時文件做合并, 生成最終的正式輸出文件,然后等待reduce task來拉數據

詳細步驟

  1. 讀取數據組件 InputFormat (默認 TextInputFormat) 會通過 getSplits 方法對輸入目錄 中文件進行邏輯切片規劃得到 block , 有多少個 block 就對應啟動多少個 MapTask

  2. 將輸入文件切分為 block 之后, 由 RecordReader 對象 (默認是LineRecordReader) 進 行讀取, 以 \n 作為分隔符, 讀取一行數據, 返回 <key,value> . Key 表示每行首字符偏 移值, Value 表示這一行文本內容

  3. 讀取 block 返回 <key,value> , 進入用戶自己繼承的 Mapper 類中,執行用戶重寫 的 map 函數, RecordReader 讀取一行這里調用一次

  4. Mapper 邏輯結束之后, 將 Mapper 的每條結果通過 context.write 集. 在 collect 中, 會先對其進行分區處理,默認使用 HashPartitioner

    1. MapReduce 提供 Partitioner 接口, 它的作用就是根據 Key 或 Value 及 Reducer 的數量來決定當前的這對輸出數據最終應該交由哪個 Reduce task 處理, 默認對 Key Hash 后再以 Reducer 數量取模. 默認的取模方式只是為 了平均 Reducer 的處理能力, 如果用戶自己對 Partitioner 有需求, 可以訂制并設置 到 Job 上
  5. 接下來, 會將數據寫入內存, 內存中這片區域叫做環形緩沖區, 緩沖區的作用是批量收集 Mapper 結果, 減少磁盤 IO 的影響. 我們的 Key/Value 對以及 Partition 的結果都會被寫入 緩沖區. 當然, 寫入之前,Key 與 Value 值都會被序列化成字節數組

    1. 環形緩沖區其實是一個數組, 數組中存放著 Key, Value 的序列化數據和 Key, Value 的元數據信息, 包括 Partition, Key 的起始位置, Value 的起始位置以及 Value 的長度. 環形結構是一個抽象概念

    2. 緩沖區是有大小限制, 默認是 100MB. 當 Mapper 的輸出結果很多時, 就可能會撐 爆內存, 所以需要在一定條件下將緩沖區中的數據臨時寫入磁盤, 然后重新利用 這塊緩沖區. 這個從內存往磁盤寫數據的過程被稱為 Spill, 中文可譯為溢寫. 這個 溢寫是由單獨線程來完成, 不影響往緩沖區寫 Mapper 結果的線程. 溢寫線程啟動 時不應該阻止 Mapper 的結果輸出, 所以整個緩沖區有個溢寫的比例 spill.percent . 這個比例默認是 0.8, 也就是當緩沖區的數據已經達到閾值 buffer size * spill percent = 100MB * 0.8 = 80MB , 溢寫線程啟動, 鎖定這 80MB 的內存, 執行溢寫過程. Mapper 的輸出結果還可以往剩下的 20MB 內存中寫, 互不影響

  6. 當溢寫線程啟動后, 需要對這 80MB 空間內的 Key 做排序 (Sort). 排序是 MapReduce 模型 默認的行為, 這里的排序也是對序列化的字節做的排序

    1. 如果 Job 設置過 Combiner, 那么現在就是使用 Combiner 的時候了. 將有相同 Key 的 Key/Value 對的 Value 加起來, 減少溢寫到磁盤的數據量. Combiner 會優化 MapReduce 的中間結果, 所以它在整個模型中會多次使用

    2. 那哪些場景才能使用 Combiner 呢? 從這里分析, Combiner 的輸出是 Reducer 的 輸入, Combiner 絕不能改變最終的計算結果. Combiner 只應該用于那種 Reduce 的輸入 Key/Value 與輸出 Key/Value 類型完全一致, 且不影響最終結果的場景. 比 如累加, 最大值等. Combiner 的使用一定得慎重, 如果用好, 它對 Job 執行效率有 幫助, 反之會影響 Reducer 的最終結果

  7. 合并溢寫文件, 每次溢寫會在磁盤上生成一個臨時文件 (寫之前判斷是否有 Combiner), 如 果 Mapper 的輸出結果真的很大, 有多次這樣的溢寫發生, 磁盤上相應的就會有多個臨時文 件存在. 當整個數據處理結束之后開始對磁盤中的臨時文件進行 Merge 合并, 因為最終的 文件只有一個, 寫入磁盤, 并且為這個文件提供了一個索引文件, 以記錄每個reduce對應數 據的偏移量

配置 默認值 解釋
mapreduce.task.io.sort.mb 100 設置環型緩沖區的內存值大小
mapreduce.map.sort.spill.percent 0.8 設置溢寫的比例
mapreduce.cluster.local.dir ${hadoop.tmp.dir}/mapred/local 溢寫數據目錄
mapreduce.task.io.sort.factor 10 設置一次合并多少個溢寫文件

2. ReduceTask 工作機制

image

Reduce 大致分為 copy、sort、reduce 三個階段,重點在前兩個階段。copy 階段包含一個 eventFetcher 來獲取已完成的 map 列表,由 Fetcher 線程去 copy 數據,在此過程中會啟動兩 個 merge 線程,分別為 inMemoryMerger 和 onDiskMerger,分別將內存中的數據 merge 到磁 盤和將磁盤中的數據進行 merge。待數據 copy 完成之后,copy 階段就完成了,開始進行 sort階段,sort 階段主要是執行 finalMerge 操作,純粹的 sort 階段,完成之后就是 reduce 階段, 調用用戶定義的 reduce 函數進行處理

詳細步驟

  1. Copy階段,簡單地拉取數據。Reduce進程啟動一些數據copy線程(Fetcher),通過HTTP 方式請求maptask獲取屬于自己的文件。
  2. Merge階段 。這里的merge如map端的merge動作,只是數組中存放的是不同map端 copy來的數值。Copy過來的數據會先放入內存緩沖區中,這里的緩沖區大小要比map端 的更為靈活。merge有三種形式:內存到內存;內存到磁盤;磁盤到磁盤。默認情況下第 一種形式不啟用。當內存中的數據量到達一定閾值,就啟動內存到磁盤的merge。與map 端類似,這也是溢寫的過程,這個過程中如果你設置有Combiner,也是會啟用的,然后 在磁盤中生成了眾多的溢寫文件。第二種merge方式一直在運行,直到沒有map端的數據 時才結束,然后啟動第三種磁盤到磁盤的merge方式生成最終的文件。
  3. 合并排序 。把分散的數據合并成一個大的數據后,還會再對合并后的數據排序。
  4. 對排序后的鍵值對調用reduce方法,鍵相等的鍵值對調用一次reduce方法,每次調用會產生零個或者多個鍵值對,最后把這些輸出的鍵值對寫入到HDFS文件中。

3. Shuffle 過程

map 階段處理的數據如何傳遞給 reduce 階段,是 MapReduce 框架中最關鍵的一個流程,這 個流程就叫 shuwle shuwle: 洗牌、發牌 ——(核心機制:數據分區,排序,分組,規約,合并 等過程)

image

shuffle 是 Mapreduce 的核心,它分布在 Mapreduce 的 map 階段和 reduce 階段。一般把從 Map 產生輸出開始到 Reduce 取得數據作為輸入之前的過程稱作 shuffle。

  1. Collect階段,將 MapTask 的結果輸出到默認大小為 100M 的環形緩沖區,保存的是 key/value,Partition 分區信息等。
  2. Spill階段 :當內存中的數據量達到一定的閥值的時候,就會將數據寫入本地磁盤, 在將數據寫入磁盤之前需要對數據進行一次排序的操作,如果配置了 combiner,還會將 有相同分區號和 key 的數據進行排序。
  3. Merge階段 :把所有溢出的臨時文件進行一次合并操作,以確保一個 MapTask 最終只產生一個中間數據文件。
  4. Copy階段 :ReduceTask 啟動 Fetcher 線程到已經完成 MapTask 的節點上復制一份屬于 自己的數據,這些數據默認會保存在內存的緩沖區中,當內存的緩沖區達到一定的閥值 的時候,就會將數據寫到磁盤之上。
  5. Merge階段 :在 ReduceTask 遠程復制數據的同時,會在后臺開啟兩個線程對內存到本地的數據文件進行合并操作。
  6. Sort階段 :在對數據進行合并的同時,會進行排序操作,由于 MapTask 階段已經對數 據進行了局部的排序,ReduceTask 只需保證 Copy 的數據的最終整體有效性即可。 Shuwle 中的緩沖區大小會影響到 mapreduce 程序的執行效率,原則上說,緩沖區越大, 磁盤io的次數越少,執行速度就越快 緩沖區的大小可以通過參數調整, 參數:mapreduce.task.io.sort.mb 默認100M

4. 整個工作流程圖

0-MapReduce工作機制-全流程
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。