控制map個數的核心原始碼
1 long minSize = Math.max(getFormatMinSplitSize(), getMinSplitSize(job)); 2 3 //getFormatMinSplitSize 預設返回1,getMinSplitSize 為使用者設定的最小分片數, 如果使用者設定的大於1,則為使用者設定的最小分片數 4 long maxSize = getMaxSplitSize(job); 5 6 //getMaxSplitSize為使用者設定的最大分片數,預設最大為long 9223372036854775807L 7 8 long splitSize = computeSplitSize(blockSize, minSize, 9 maxSize); 10 11 protected long computeSplitSize(long blockSize, long minSize, long maxSize) { 12 return Math.max(minSize, Math.min(maxSize, blockSize)); 13 }
由上述程式碼可以看出在
maxSize預設等於long(長整形)
blockSize預設在hadoop2.0之後為128M
minSize預設等於1
因此預設的切片大小splitSize等於128M也就是說等於塊大小
一個切片對應於一個map任務,因此在預設情況下一個塊對應於一個map任務。
要想人為控制map的個數可以從minSize和MaxSize入手。
想要增加map的個數,可以將maxSize調整小於blockSize;想要減小map的個數,可以調整minSize>blockSize。
具體調整可以在job配置中增加如下配置
FileInputFormat.setMinInputSplitSize(job, 301349250);//設定minSize FileInputFormat.setMaxInputSplitSize(job, 10000);//設定maxSize
在實驗中,
測試 檔案大小 297M(311349250)
塊大小128M
測試程式碼
FileInputFormat.setMinInputSplitSize(job, 301349250);
FileInputFormat.setMaxInputSplitSize(job, 10000);
測試後Map個數為1,由上面分片公式算出分片大小為301349250, 比 311349250小, 理論應該為兩個map, 這是為什麼呢?在上原始碼
while (bytesRemaining / splitSize > 1.1D) { int blkIndex = getBlockIndex(blkLocations, length - bytesRemaining); splits.add(makeSplit(path, length - bytesRemaining, splitSize, blkLocations[blkIndex].getHosts())); bytesRemaining -= splitSize; }
可以看出只要剩餘的檔案大小不超過分片大小的1.1倍, 則會分到一個分片中,避免開兩個MAP, 其中一個執行資料太小,浪費資源。
總結,分片過程大概為,先遍歷目標檔案,過濾部分不符合要求的檔案, 然後新增到列表,然後按照檔名來切分分片 (大小為前面計算分片大小的公式, 最後有個檔案尾可能合併,其實常寫網路程式的都知道), 然後新增到分片列表,然後每個分片讀取自身對應的部分給MAP處理