MapReduce 中 map 分片大小確定 和map任務數的計算
Hadoop中在計算一個JOB需要的map數之前首先要計算分片的大小。計算分片大小的公式是:
goalSize = totalSize / mapred.map.tasks
minSize = max {mapred.min.split.size, minSplitSize}
splitSize = max (minSize, min(goalSize, dfs.block.size))
totalSize是一個JOB的所有map總的輸入大小,即Map input bytes。引數mapred.map.tasks的預設值是2,我們可以更改這個引數的值。計算好了goalSize之後還要確定上限和下限。
下限是max {mapred.min.split.size, minSplitSize} 。引數mapred.min.split.size的預設值為1個位元組,minSplitSize隨著File Format的不同而不同。
上限是dfs.block.size,它的預設值是64兆。
舉幾個例子,例如Map input bytes是100兆,mapred.map.tasks預設值為2,那麼分片大小就是50兆;如果我們把mapred.map.tasks改成1,那分片大小就變成了64兆。
計算好了分片大小之後接下來計算map數。Map數的計算是以檔案為單位的,針對每一個檔案做一個迴圈:
1. 檔案大小/splitsize>1.1,建立一個split,這個split的大小=splitsize,檔案剩餘大小=檔案大小-splitsize
2. 檔案剩餘大小/splitsize<1.1,剩餘的部分作為一個split
舉幾個例子:
1. input只有一個檔案,大小為100M,splitsize=blocksize,則map數為2,第一個map處理的分片為64M,第二個為36M
2. input只有一個檔案,大小為65M,splitsize=blocksize,則map數為1,處理的分片大小為65M (因為65/64<1.1)
3. input只有一個檔案,大小為129M,splitsize=blocksize,則map數為2,第一個map處理的分片為64M,第二個為65M
4. input有兩個檔案,大小為100M和20M,splitsize=blocksize,則map數為3,第一個檔案分為兩個map,第一個map處理的分片為64M,第二個為36M,第二個檔案分為一個map,處理的分片大小為20M
5. input有10個檔案,每個大小10M,splitsize=blocksize,則map數為10,每個map處理的分片大小為10M
再看2個更特殊的例子:
1. 輸入檔案有2個,分別為40M和20M,dfs.block.size = 64M, mapred.map.tasks採用預設值2。那麼splitSize = 30M ,map數實際為3,第一個檔案分為2個map,第一個map處理的分片大小為30M,第二個map為10M;第二個檔案分為1個map,大小為20M
2. 輸入檔案有2個,分別為40M和20M,dfs.block.size = 64M, mapred.map.tasks手工設定為1。
那麼splitSize = 60M ,map數實際為2,第一個檔案分為1個map,處理的分片大小為40M;第二個檔案分為1個map,大小為20M
通過這2個特殊的例子可以看到mapred.map.tasks並不是設定的越大,JOB執行的效率就越高。同時,Hadoop在處理小檔案時效率也會變差。
根據分片與map數的計算方法可以得出結論,一個map處理的分片最大不超過dfs.block.size * 1.1 ,預設情況下是70.4兆。但是有2個特例:
1. Hive中合併小檔案的map only JOB,此JOB只會有一個或很少的幾個map。
2. 輸入檔案格式為壓縮的Text File,因為壓縮的文字格式不知道如何拆分,所以也只能用一個map。