Hadoop Mapper
MapReduce - Mapper
主要是讀取InputSplit的每一個Key,Value對並進行處理
public class Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT> {
/**
* 預處理,僅在map task啓動時運行一次
*/
protected void setup(Context context) throws IOException, InterruptedException {
}
/**
* 對於InputSplit中的每一對<key, value>都會運行一次
*/
@SuppressWarnings("unchecked")
protected void map(KEYIN key, VALUEIN value, Context context) throws IOException, InterruptedException {
context.write((KEYOUT) key, (VALUEOUT) value);
}
/**
* 掃尾工作,比如關閉流等
*/
protected void cleanup(Context context) throws IOException, InterruptedException {
}
/**
* map task的驅動器
*/
public void run(Context context) throws IOException, InterruptedException {
setup(context);
while (context.nextKeyValue()) {
map(context.getCurrentKey(), context.getCurrentValue(), context);
}
cleanup(context);
}
}
public class MapContext<KEYIN, VALUEIN, KEYOUT, VALUEOUT> extends TaskInputOutputContext<KEYIN, VALUEIN, KEYOUT, VALUEOUT> {
private RecordReader<KEYIN, VALUEIN> reader;
private InputSplit split;
/**
* Get the input split for this map.
*/
public InputSplit getInputSplit() {
return split;
}
@Override
public KEYIN getCurrentKey() throws IOException, InterruptedException {
return reader.getCurrentKey();
}
@Override
public VALUEIN getCurrentValue() throws IOException, InterruptedException {
return reader.getCurrentValue();
}
@Override
public boolean nextKeyValue() throws IOException, InterruptedException {
return reader.nextKeyValue();
}
}
Hadoop Shuffle
MapReduce - Shuffle
對Map的結果進行排序並傳輸到Reduce進行處理 Map的結果並不是直接存放到硬盤,而是利用緩存做一些預排序處理 Map會調用Combiner,壓縮,按key進行分區、排序等,儘量減少結果的大小 每個Map完成後都會通知Task,然後Reduce就可以進行處理
Map端
當Map程序開始產生結果的時候,並不是直接寫到文件的,而是利用緩存做一些排序方面的預處理操作
每個Map任務都有一個循環內存緩衝區(默認100MB),當緩存的內容達到80%時,後臺線程開始將內容寫到文件,此時Map任務可以繼續輸出結果,但如果緩衝區滿了,Map任務則需要等待
寫文件使用round-robin方式。在寫入文件之前,先將數據按照Reduce進行分區。對於每一個分區,都會在內存中根據key進行排序,如果配置了Combiner,則排序後執行Combiner(Combine之後可以減少寫入文件和傳輸的數據)
每次結果達到緩衝區的閥值時,都會創建一個文件,在Map結束時,可能會產生大量的文件。在Map完成前,會將這些文件進行合併和排序。如果文件的數量超過3個,則合併後會再次運行Combiner(1、2個文件就沒有必要了)
如果配置了壓縮,則最終寫入的文件會先進行壓縮,這樣可以減少寫入和傳輸的數據
一旦Map完成,則通知任務管理器,此時Reduce就可以開始複製結果數據
Reduce端
Map的結果文件都存放到運行Map任務的機器的本地硬盤中
如果Map的結果很少,則直接放到內存,否則寫入文件中
同時後臺線程將這些文件進行合併和排序到一個更大的文件中(如果文件是壓縮的,則需要先解壓)
當所有的Map結果都被複制和合並後,就會調用Reduce方法
Reduce結果會寫入到HDFS中
調優
一般的原則是給shuffle分配儘可能多的內存,但前提是要保證Map、Reduce任務有足夠的內存
對於Map,主要就是避免把文件寫入磁盤,例如使用Combiner,增大io.sort.mb的值
對於Reduce,主要是把Map的結果儘可能地保存到內存中,同樣也是要避免把中間結果寫入磁盤。默認情況下,所有的內存都是分配給Reduce方法的,如果Reduce方法不怎麼消耗內存,可以mapred.inmem.merge.threshold設成0,mapred.job.reduce.input.buffer.percent設成1.0
在任務監控中可通過Spilled records counter來監控寫入磁盤的數,但這個值是包括map和reduce的
對於IO方面,可以Map的結果可以使用壓縮,同時增大buffer size(io.file.buffer.size,默認4kb)
配置
屬性 | 默認值 | 描述 |
---|---|---|
io.sort.mb | 100 | 映射輸出分類時所使用緩衝區的大小. |
io.sort.record.percent | 0.05 | 剩餘空間用於映射輸出自身記錄.在1.X發佈後去除此屬性.隨機代碼用於使用映射所有內存並記錄信息. |
io.sort.spill.percent | 0.80 | 針對映射輸出內存緩衝和記錄索引的閾值使用比例. |
io.sort.factor | 10 | 文件分類時合併流的最大數量。此屬性也用於reduce。通常把數字設爲100. |
min.num.spills.for.combine | 3 | 組合運行所需最小溢出文件數目. |
mapred.compress.map.output | false | 壓縮映射輸出. |
mapred.map.output.compression.codec | DefaultCodec | 映射輸出所需的壓縮解編碼器. |
mapred.reduce.parallel.copies | 5 | 用於向reducer傳送映射輸出的線程數目. |
mapred.reduce.copy.backoff | 300 | 時間的最大數量,以秒爲單位,這段時間內若reducer失敗則會反覆嘗試傳輸 |
io.sort.factor | 10 | 組合運行所需最大溢出文件數目. |
mapred.job.shuffle.input.buffer.percent | 0.70 | 隨機複製階段映射輸出緩衝器的堆棧大小比例 |
mapred.job.shuffle.merge.percent | 0.66 | 用於啓動合併輸出進程和磁盤傳輸的映射輸出緩衝器的閥值使用比例 |
mapred.inmem.merge.threshold | 1000 | 用於啓動合併輸出和磁盤傳輸進程的映射輸出的閥值數目。小於等於0意味着沒有門檻,而溢出行爲由 mapred.job.shuffle.merge.percent單獨管理. |
mapred.job.reduce.input.buffer.percent | 0.0 | 用於減少內存映射輸出的堆棧大小比例,內存中映射大小不得超出此值。若reducer需要較少內存則可以提高該值. |