Hadoop-2.4.1學習之怎樣確定Mapper數量

來源:互聯網
上載者:User

標籤:ffffff   大小   while   instance   產生   lis   tail   並行   etc   

       MapReduce架構的優勢是能夠在叢集中並行運行mapper和reducer任務,那怎樣確定mapper和reducer的數量呢,或者說怎樣以編程的方式控製作業啟動的mapper和reducer數量呢?在《Hadoop-2.4.1學習之Mapper和Reducer》中以前提及建議reducer的數量為(0.95~1.75 ) * 節點數量 * 每一個節點上最大的容器數,並可用法Job.setNumReduceTasks(int)。mapper的數量由輸入檔案的大小確定。且沒有相應的setNumMapTasks方法,但能夠通過Configuration.set(JobContext.NUM_MAPS, int)設定,當中JobContext.NUM_MAPS的值為mapreduce.job.maps,而在Hadoop的官方網站上對該參數的描寫敘述為與MapReduce架構和作業配置巧妙地互動。而且設定起來更加複雜。

從這樣一句含糊不清的話無法得知到底怎樣確定mapper的數量。顯然僅僅能求助於源碼了。

      在Hadoop中MapReduce作業通過JobSubmitter類的submitJobInternal(Jobjob, Cluster cluster)方法向系統提交作業(該方法不僅設定mapper數量。還運行了一些其他動作如檢查輸出格式等,感興趣的能夠參考源碼),在該方法中與設定mapper有關的代碼例如以下:

int maps = writeSplits(job, submitJobDir);conf.setInt(MRJobConfig.NUM_MAPS, maps);LOG.info("number of splits:" + maps);

      方法writeSplits返回mapper的數量,該方法的源碼例如以下:

private int writeSplits(org.apache.hadoop.mapreduce.JobContext job,Path jobSubmitDir) throws IOException,InterruptedException, ClassNotFoundException {    JobConf jConf = (JobConf)job.getConfiguration();    int maps;    if (jConf.getUseNewMapper()) {      maps = writeNewSplits(job, jobSubmitDir);    } else {      maps = writeOldSplits(jConf, jobSubmitDir);    }    return maps;  }

      在該方法中,依據是否使用了新版本號碼的JobContext而使用不同的方法計算mapper數量。實際情況是jConf.getUseNewMapper()將返回true,因此將運行writeNewSplits(job,jobSubmitDir)語句,該方法的源碼例如以下:

Configuration conf = job.getConfiguration();InputFormat<?, ?

> input = ReflectionUtils.newInstance(job.getInputFormatClass(), conf);List<InputSplit> splits = input.getSplits(job);T[] array = (T[]) splits.toArray(new InputSplit[splits.size()]);// sort the splits into order based on size, so that the biggest// go firstArrays.sort(array, new SplitComparator());JobSplitWriter.createSplitFiles(jobSubmitDir, conf, jobSubmitDir.getFileSystem(conf), array);return array.length;

      通過上面的代碼能夠得知,實際的mapper數量為輸入分區的數量,而分區的數量又由使用的輸入格式決定,默覺得TextInputFormat,該類為FileInputFormat的子類。確定分區數量的任務交由FileInputFormat的getSplits(job)完畢,在此補充一下FileInputFormat繼承自抽象類別InputFormat,該類定義了MapReduce作業的輸入規範,當中的抽象方法List<InputSplit> getSplits(JobContext context)定義了怎樣將輸入切割為InputSplit。不同的輸入有不同的分隔邏輯,而分隔得到的每一個InputSplit交由不同的mapper處理,因此該方法的傳回值確定了mapper的數量。以下將分為兩部分學習該方法是怎樣在FileInputFormat中實現的,為了將注意力集中在最重要的部分。對日誌輸出等資訊將不做介紹,完整的實現能夠參考源碼。

      首先是第一部分,該部分代碼計算了最大InputSplit和最小InputSplit的值,例如以下:

long minSize = Math.max(getFormatMinSplitSize(), getMinSplitSize(job));long maxSize = getMaxSplitSize(job);

      當中的getMinSplitSize和getMaxSplitSize方法分別用於擷取最小InputSplit和最大InputSplit的值。相應的配置參數分別為mapreduce.input.fileinputformat.split.minsize。預設值為1L和mapreduce.input.fileinputformat.split.maxsize,預設值為Long.MAX_VALUE,十六進位數值為 0x7fffffffffffffffL,相應的十進位為9223372036854775807,getFormatMinSplitSize方法返回該輸入格式下InputSplit的下限。

以上數位單位都是byte。由此得出minSize的大小為1L。maxSize的大小為Long.MAX_VALUE。

      其次是產生InputSplit的第二部分。在該部分將產生包括InputSplit的List,而List的大小為InputSplit的數量,進而確定了mapper的數量。當中重要的代碼為:

if (isSplitable(job, path)) {          long blockSize = file.getBlockSize();          long splitSize = computeSplitSize(blockSize, minSize, maxSize);          long bytesRemaining = length;          while (((double) bytesRemaining)/splitSize > SPLIT_SLOP) {            int blkIndex = getBlockIndex(blkLocations, length-bytesRemaining);            splits.add(makeSplit(path, length-bytesRemaining, splitSize,                                     blkLocations[blkIndex].getHosts()));            bytesRemaining -= splitSize;          }          if (bytesRemaining != 0) {            int blkIndex = getBlockIndex(blkLocations, length-bytesRemaining);            splits.add(makeSplit(path, length-bytesRemaining, bytesRemaining,                       blkLocations[blkIndex].getHosts()));          }}

      blockSize的值為參數dfs.blocksize的值,默覺得128M。方法computeSplitSize(blockSize, minSize, maxSize)依據blockSize,minSize。maxSize確定InputSplit的大小,源碼例如以下:

Math.max(minSize, Math.min(maxSize, blockSize))

      從該代碼並結合第一部分的分析能夠得知,InputSplit的大小取決於dfs.blocksiz、mapreduce.input.fileinputformat.split.minsize、mapreduce.input.fileinputformat.split.maxsize和所使用的輸入格式。

在輸入格式為TextInputFormat的情況下,且不改動InputSplit的最大值和最小值的情況,InputSplit的終於值為dfs.blocksize的值。

變數SPLIT_SLOP的值為1.1。決定了當剩餘檔案大小多大時停止依照變數splitSize切割檔案。

依據代碼可知,當剩餘檔案小於等於1.1倍splitSize時,將把剩餘的檔案做為一個InputSplit。即最後一個InputSplit的大小最大為1.1倍splitSize。

總結      本文分析了在輸入格式為預設的TextInputFormat的情況,怎樣確定mapper的數量。在不改動源碼的情況下(改動輸入格式的InputSplit下限)。程式猿能夠通過設定dfs.blocksiz、mapreduce.input.fileinputformat.split.minsize、mapreduce.input.fileinputformat.split.maxsize參數的值設定InputSplit的大小來影響InputSplit的數量。進而決定mapper的數量。

當輸入為其他格式時,處理邏輯又不同樣了,比方當輸入格式為DBInputFormat時。會依據輸入表的行數(記錄數)決定mapper的數量。很多其他細節能夠參考源碼。


Hadoop-2.4.1學習之怎樣確定Mapper數量

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.