MapReduce的MapTask數量如何確定?

2021-09-17 04:35:12 字數 4720 閱讀 3008

在技術領域,尤其是開源技術領域,版本變遷速度極快,有些介紹原理機制的文章可能並不能適合當前的技術版本,有時候找到一篇文章中關於某問題的解決方案,可能並不奏效,其原因何在?版本不同!

在文章中說清楚技術原理分析針對的版本是一件極其道德的事情。

hadoop:2.7.3

在進行map計算之前,mapreduce框架會根據輸入檔案計算輸入資料分片(input split),每個資料分片針對乙個map任務,資料分片儲存的並非資料本身,而是乙個分片長度和乙個記錄資料的位置的陣列。

那麼資料分成多少片(how much splits)是如何確定的呢?

影響map個數(split個數)的主要因素有:

檔案的大小。當塊(dfs.block.size)為128m時,如果輸入檔案為128m,會被劃分為1個split;當塊為256m,會被劃分為2個split。

檔案的個數。fileinputformat按照檔案分割split,並且只會分割大檔案,即那些大小超過hdfs塊的大小的檔案。如果hdfs中dfs.block.size設定為128m,而輸入的目錄中檔案有100個,則劃分後的split個數至少為100個。

splitsize的大小。分片是按照splitszie的大小進行分割的,乙個split的大小在沒有設定的情況下,預設等於hdfs block的大小。

已知以下引數

input_file_num : 輸入檔案的個數

block_size : hdfs的檔案塊大小,2.7.3預設為128m,可以通過hdfs-site.xml中的dfs.block.size引數進行設定

total_size : 輸入檔案整體的大小,由框架迴圈疊加計算

maptask的數量計算原則為:

(1)預設map個數

如果不進行任何設定,預設的map個數是和blcok_size相關的。

default_num = total_size / block_size;

(2)自定義設定分片的minsize、maxsize

如果在mapreduce的驅動程式(main方法)中通過以下方法設定了分片的最小或最大的大小

//設定最小分片大小,單位byte

fileinputformat.

setmininputsplitsize

(job,

1024

*1024

*10l)

;//10mb

//設定最大分片大小,單位byte

fileinputformat.

setmaxinputsplitsize

(job,

1024l)

;//1kb

應用程式可以通過資料分片的最大和最小大小兩個引數來對splitsize進行調節,則計算方式就變成了

splitsize=math.

max(minsize, math.

min(maxsize, blocksize)

其中maxsize即方法setmaxinputsplitsize設定的值,minsize即方法·setmininputsplitsize·設定的值。

其設定原則就是

要增加map的個數,調整maxsizeblocksize。

方式1:在客戶端提交任務時可在日誌中檢視,如圖

方式2:如果開啟了hadoop的history server,可在ui介面中看到maptask的數量。

先來了解兩個概念

block塊(資料塊,物理劃分)

block是hdfs中的基本儲存單位,hadoop1.x預設大小為64m而hadoop2.x預設塊大小為128m。檔案上傳到hdfs,就要劃分資料成塊,這裡的劃分屬於物理的劃分(實現機制也就是設定乙個read方法,每次限制最多讀128m的資料後呼叫write進行寫入到hdfs),塊的大小可通過dfs.block.size配置。block採用冗餘機制保證資料的安全:預設為3份,可通過dfs.replication配置。

注意:當更改塊大小的配置後,新上傳的檔案的塊大小為新配置的值,以前上傳的檔案的塊大小為以前的配置值。

split分片(資料分片,邏輯劃分)

hadoop中split劃分屬於邏輯上的劃分,目的只是為了讓map task更好地獲取資料。split是通過hadoop中的inputformat介面中的getsplits()方法得到的。

splitsize由以下變數共同決定:

(1)totalsize:整個mapreduce job輸入檔案的總大小,框架迴圈計算輸入目錄下的所有檔案的大小之和。

long totalsize =0;

// compute total size

for(filestatus file: files)

totalsize += file.

getlen()

;}

(2)minsize:資料分片的最小值,預設為1

(3)maxsize:資料分片的最大值,預設為integer最大值,即integer.max_value

hadoop2.7.3版本分片大小計算原始碼如下:

org.apache.hadoop.mapreduce.lib.input.fileinputformat

long minsize = math.

max(

getformatminsplitsize()

,getminsplitsize

(job));

long maxsize =

getmaxsplitsize

(job)

;long blocksize = file.

getblocksize()

;long splitsize =

computesplitsize

(blocksize, minsize, maxsize)

;protected

long

computesplitsize

(long blocksize,

long minsize,

long maxsize)

分片確定的臨界問題

分片大小的數量一定是按照公式math.max(minsize, math.min(maxsize, blocksize))計算的嗎?

可做以下試驗:檔案大小 297m(311349250),塊大小128m

測試**

fileinputformat.

setmininputsplitsize

(job,

301349250

);

fileinputformat.

setmaxinputsplitsize

(job,

10000

);

由上面分片公式算出分片大小為301349250, 比 311349250小, 理論應該為2個map, 但實際測試後map個數為1, 這是為什麼呢?

分片的計算中,會考慮空間利用問題,每次分出乙個分片後,都會判斷剩下的資料能否在一定的比率(slop變數,預設10%)內壓縮到當前分片中,如果不大於預設比率1.1,則會壓縮到當前分片中。原始碼如下

private

static

final

double split_slop =

1.1;

// 10% slop

long bytesremaining = length;

while((

(double

) bytesremaining)

/splitsize > split_slop)

4.1 maptask數量設定不當帶來的問題

4.2maptask數量控制方法

(1)如果想增加map個數,則通過fileinputformat.setmaxinputsplitsize(job,long bytes)方法設定最大資料分片大小為乙個小於預設blocksize的值,越小map數量越多。

(2)如果想減小map個數,則fileinputformat.setmininputsplitsize(job,long bytes)方法設定最小資料分片大小為乙個大於預設blocksize的值,越大map數量越少。

(3)如果輸入中有很多小檔案,依然想減少map個數,則需要將小檔案使用hdfs提供的api合併為大檔案,然後使用方法2。

reduce任務是乙個資料聚合的步驟,數量預設為1。使用過多的reduce任務則意味著複雜的shuffle,並使輸出檔案數量激增。而reduce的個數設定相比map的個數設定就要簡單的多,只需要設定在驅動程式中通過job.setnumreducetasks(int n)即可。

Map Reduce的過程解析

map reduce的過程首先是由客戶端提交乙個任務開始的。提交任務主要是通過jobclient.runjob jobconf 靜態函式實現的 public static runningjob runjob jobconf job throws ioexception finally finally...

Mapreduce的輸入格式

map k1,v1 list k2,v2 reduce k2,list v2 list k3,v3 reduce的輸入型別必須與map函式的輸出型別相同 combine的輸入輸出鍵值型別必須相同,也就是k2,v2 static class reducer extends reudcer partio...

MapReduce實現的PageRank原理

pagerank手工計算得出的值見帖子 這個值有助於我們驗證下面mr計算是不是正確 首先假設有兩個節點a和b 原始矩陣如tiger老師的幻燈片第九頁 a 1 網頁1和2儲存在節點a上 網頁3和4儲存在節點b上 由於a在a上很容易計算1和2的出鏈 根據mr的本地運算的思想,網頁1和2的處理必在a上完成...