Hive中Map任務和Reduce任務數計算原理
MapReduce原理
-
Map階段(以
FileInputFormat
爲例)
步驟:map, partition, sort, combinerInputFormat
負責計算分片,一個分片對應一個Map任務,InputFormat
而且還負責創建RecordReader
,通過RecordReader
的next()
方法,然後循環調用map()
方法map()
方法的輸入爲一行文本,處理的結果先是寫到內存緩衝區,達到閾值之後,溢寫到磁盤,如果多次溢出,則會有多個溢出文件,這些溢出文件經過了分區,排序,而且還可能作過Combiner
,map任務結束之後,多個溢出文件會合併成一個,結果寫在本地
-
Reduce階段
步驟:copy, sort, reduce- reduce階段先會進行copy,如果copy過來的文件很小,則直接copy到內存中,如果文件較大,則copy到磁盤
- copy完成之後,會進行一個歸併,由於在map端已經作過排序,所以,歸併其實是在將多個有序的文件合併成一個有序的文件,這個文件中,一個key會生成一條記錄,value爲這個key對應的數組
- 對歸併後的文件循環調用
reduce()
方法,對每個key進行處理。
Map數量
hive的Map數量與分片大數量一致,一個分片生成一個Map任務,分片不是數據本身,是記錄了數據的位置和長度,長度用於考慮優先運行,位置用於查找數據,一個分片大小的計算取決於使用的InputFormat
(具體使用哪個Inputformat
可以在執行計劃中查看到),不同的InputFormat
計算分片的邏輯可能有所不同。
Hadoop程序中,對於FileInputformat
,分片的計算方式爲:
- 分片大小
splitSize
=Math.max(minSize, Math.min(goalSize, blockSize));
long goalSize = totalSize / (numSplits == 0 ? 1 : numSplits);
,totalSize爲輸入文件的總大小,numSplits爲用戶配置的map數量(mapreduce.job.maps
)minSize
,用戶配置的最小分片大小blockSize
,文件塊大小,默認128M
如果小文件太多,默認情況下會生成太多的map,這樣很影響效率,所以,對於CombineFileInputFormat
,根據節點和機架的因素,會把多個小文件合併成一個分片,生成更少的map數
配置解釋:
mapreduce.input.fileinputformat.split.maxsize
,分片的最大size,默認256000000,即256Mbmapreduce.input.fileinputformat.split.minsize.per.node
,最小分片大小,單位byte,默認大小1,如果想配置成256Mb,則爲256 * 1000 * 1000
,需要注意配置???mapreduce.input.fileinputformat.split.minsize.per.rack
mapreduce.job.maps
,每個jobe的map任務數量,默認2
Map任務數量調整策略
影響Map數量的因素:文件大小,文件數量,塊大小,配置的Map數量,`InputFormat`類
- 調大Map數量
- 調小`mapreduce.input.fileinputformat.split.maxsize`(`mapred.max.split.size`已過時),當值小於`blockSize`時纔有效
- 調小Map數量
- 調大`mapreduce.input.fileinputformat.split.minsize.per.node`和`mapreduce.input.fileinputformat.split.minsize.per.rack`,當這二者的值大於blockSize纔有效,此時最好配合使用`mapreduce.job.max.split.locations`(表示分片最大的location,默認大小爲10,表示一個map處理的split的文件不能超過10個節點),如果超過10,則可能會導致數據錯誤
Reduce數量
Reduce任務的數量,首先是取用戶設置的配置reduce數量,如果在沒有指定數量的時候,是由程序自動估算出來的,具體情況如下:
1、Map Join的時候,沒有reduce數量
2、如果有配置mapreduce.job.reduces
,則使用這個值作爲reduce數量
3、如果沒有配置mapreduce.job.reduces
,則進行reduce估算過程,具體的估算過程如下
- 獲取
bytesPerReducer
,由hive.exec.reducers.bytes.per.reducer
配置,默認256Mb - 獲取
maxReducers
,由hive.exec.reducers.max
配置,默認1009 - 計算
samplePercentage
- 計算
totalInputFileSize
,總的輸入文件的大小 - 計算
powersOfTwo
,如果使用bucket,並且hive.exec.infer.bucket.sort.num.buckets.power.two
=true
時才生效,默認這個值爲false
再根據以下判斷邏輯計算出最終的估算的reduce數量:
double bytes = Math.max(totalInputFileSize, bytesPerReducer);
int reducers = (int) Math.ceil(bytes / bytesPerReducer);
reducers = Math.max(1, reducers);
reducers = Math.min(maxReducers, reducers);
因此,從公式中可以得出,影響reduce數量的因素包括:輸入總大小,每個reduce處理的數據量
reduce的數量與分區沒有關係,但最終生成的文件數量與分區有關係,在沒有合併reduce的輸出的情況下,reduce生成的文件數量等於分區數量或reduce數量
配置解釋:
hive.exec.reducers.bytes.per.reducer
,每個reduce處理的size,默認256Mbmapreduce.job.reduces
,reduce數量,默認爲1hive.exec.reducers.max
,reduce任務的最大數量,默認1009
reduce數量調整策略
- 調大reduce數量
- 調大
mapreduce.job.reduces
,但是要注意,如果這個值太多,會生成多餘的空文件,會浪費reduce資源,比如,分區只有20,但這個reduce數量調成30,則會申請30個reduce, 但實際只有20個有用。 - 調小
hive.exec.reducers.bytes.per.reducer
,但注意不要調太小,否則容易生成太多小文件
- 調大
注意:調大reduce的數量,並不等價於提高了併發度,有可能只是多起了reduce的個數,但依然像之前那樣傾斜
- 調小reduce數量
- 調小
mapreduce.job.reduces
,可能會影響並行度 - 調大
hive.exec.reducers.bytes.per.reducer
,但會增加每個reduce的壓力 - 調小
hive.exec.reducers.max
- 調小