MapReduce中控制Map數量

起因

近日在工作中遇到一個Hive job報錯,查看報錯信息如下:


image.png

問題猜測是由于MapJoin導致了oom,經指點后設置如下參數

set mapred.max.split.size=96000000;
set mapred.min.split.size.per.node=96000000;
set mapred.min.split.size.per.rack=96000000;

Job 成功執行。具體原理經查閱資料后,整理如下:

原理

輸入分片(Input Split)

在進行map計算前,MapReduce會根據輸入文件計算輸入分片(Input Split),每個輸入分片針對一個map任務,輸入分片存儲的并非數據本身,而是一個分片長度和一個記錄數據位置的數組
在Hadoop2.x中默認的block大小是128M,在1.x中默認的大小是64M,可是在hdfs-site.xml中自行設置:

dfs.block.size,單位是byte

分片的大小范圍可以在mapred-site.xml中設置

mapred.min.split.size,默認為1B
mapred.max.split.size,默認為Long.MAX_VALUE=9223372036854775807

分片大小

minSize=max(minSplitSize,mapred.min.split.size)
maxSize=mapred.max.split.size
splitSize=max(minSize,min(maxSize,blockSize))

所以,當沒有設置分片范圍的時候,block塊的大小決定了分片的大小,比如把一個258M的文件上傳至HDFS,假設block的大小是128M,那么它就會被分成3個block塊,與之相對應產生三個split,最終會有三個map task。這樣產生一個新的問題,繼續上面的例子,第3個block塊存的文件大小只有2M,而它的block塊的大小是128M,那它實際占用的Linux file system的空間是多大?答案是文件的實際大小;那在這種情況下,block大小的意義在于,當文件通過append操作不斷增長時,可以通過block的大小決定何時split 文件。

計算map個數

blockSize:HDFS的文件塊大小
totalSize:輸入文件大小
inputFileNum:輸入文件的數量

  • 默認map個數
    如果不進行任何設置,默認的map個數是和blockSize相關的,defaultNum=totalSize/blockSize
  • 期望個數
    可以通過參數mapred.map.tasks來設置期望的map個數,但這個只有在大于默認map個數的時候才生效,goalNum=mapred.map.tasks
  • 設置處理的文件大小
    可以通過mapred.min.split.size設置每個task處理的文件大小,但是這個大小只有在大于blockSize的時候才會生效
    splitSize=max(mapred.min.split.size,blockSize)
    splitNum=totalSize/splitSize
  • 計算的map個數
    computeMapNum=min(splitNum,max(defaultNum,goalNum))

除了以上這些配置外,MapReduce還要遵循一些原則。MapReduce的每一個map處理數據是不能跨越文件的。也就是說minMapNum>=inputFileNum,所以,最終的map個數應該為:
mapNum=max(computeMapNum,inputFileNum)

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

推薦閱讀更多精彩內容