大資料時代之hadoop(五):hadoop 分散式運算架構(MapReduce)

來源:互聯網
上載者:User

標籤:hadoop   分散式運算   mapreduce   輸入輸出格式   shuffle   

 

大資料時代之hadoop(一):hadoop安裝

大資料時代之hadoop(二):hadoop指令碼解析

大資料時代之hadoop(三):hadoop資料流(生命週期)

大資料時代之hadoop(四):hadoop Distributed File System(HDFS)

 

        hadoop的核心分為兩塊,一是分布式儲存系統-hdfs,這個我已經在上一章節大致講了一下,另一個就是hadoop的計算架構-mapreduce

     

        mapreduce其實就是一個移動式的基於key-value形式的分散式運算架構

 

        其計算分為兩個階段,map階段和reduce階段,都是對資料的處理,由於其入門非常簡單,但是若想理解其中各個環節及實現細節還是有一定程度的困難,因此我計劃在本文中只是挑幾個mapreduce的核心來進行分析講解。


 

1、MapReduce驅動程式預設值

 

        編寫mapreduce程式容易入手的其中一個原因就在於它提供了一些了的預設值,而這些預設值剛好就是供開發環境設定而設定的。雖然容易入手,但還是的理解mapreduce的精髓,因為它是mapreduce的引擎,只有理解了mapreduce的核心,當你在編寫mapreduce程式的時候,你所編寫的程式才是最終穩重的,想要的程式。廢話少說,見下面代碼:

public int run(String[] args) throws IOException {    JobConf conf = new JobConf();        /**     *預設的輸入格式,即mapper程式要處理的資料的格式,hadoop支援很多種輸入格式,下面會詳細講解,     *但TextInputFormat是最常使用的(即普通文字檔,key為LongWritable-檔案中每行的開始位移量,value為Text-文本行)。     **/    conf.setInputFormat(org.apache.hadoop.mapred.TextInputFormat.class);        /**     *真正的map任務數量取決於輸入檔案的大小以及檔案塊的大小     **/    conf.setNumMapTasks(1);        /**     *預設的mapclass,如果我們不指定自己的mapper class時,就使用這個IdentityMapper 類     **/    conf.setMapperClass(org.apache.hadoop.mapred.lib.IdentityMapper.class);        /**     * map 任務是由MapRunner負責啟動並執行,MapRunner是MapRunnable的預設實現,它順序的為每一條記錄調用一次Mapper的map()方法,詳解代碼  --重點     */    conf.setMapRunnerClass(org.apache.hadoop.mapred.MapRunner.class);        /**     * map任務輸出結果的key 和value格式     */    conf.setMapOutputKeyClass(org.apache.hadoop.io.LongWritable.class);    conf.setMapOutputValueClass(org.apache.hadoop.io.Text.class);        /**     * HashPartitioner 是預設的分區實現,它對map 任務運行後的資料進行分區,即把結果資料劃分成多個塊(每個分區對應一個reduce任務)。     * HashPartitioner是對每條 記錄的鍵進行雜湊操作以決定該記錄應該屬於哪個分區。     *      */    conf.setPartitionerClass(org.apache.hadoop.mapred.lib.HashPartitioner.class);        /**     * 設定reduce任務個數     */    conf.setNumReduceTasks(1);        /**    *預設的reduce class,如果我們不指定自己的reduce class時,就使用這個IdentityReducer 類    **/    conf.setReducerClass(org.apache.hadoop.mapred.lib.IdentityReducer.class);    /**     * 任務最終輸出結果的key 和value格式     */    conf.setOutputKeyClass(org.apache.hadoop.io.LongWritable.class);    conf.setOutputValueClass(org.apache.hadoop.io.Text.class);    /**     * 最終輸出到文字檔類型中     */    conf.setOutputFormat(org.apache.hadoop.mapred.TextOutputFormat.class);/*]*/        JobClient.runJob(conf);    return 0;  }

 

我要說的大部分都包含在了代碼的注釋裡面,除此之外,還有一點:由於java的泛型機制有很多限制:類型擦除導致運行過程中類型資訊並非一直可見,所以hadoop需要明確設定map,reduce輸入和結果類型

 

上面比較重要的就是MapRunner這個類,它是map任務啟動並執行引擎,預設實現如下:

public class MapRunner<K1, V1, K2, V2>    implements MapRunnable<K1, V1, K2, V2> {    private Mapper<K1, V1, K2, V2> mapper;  private boolean incrProcCount;  @SuppressWarnings("unchecked")  public void configure(JobConf job) {  //通過反射方式取得map 執行個體    this.mapper = ReflectionUtils.newInstance(job.getMapperClass(), job);    //increment processed counter only if skipping feature is enabled    this.incrProcCount = SkipBadRecords.getMapperMaxSkipRecords(job)>0 &&       SkipBadRecords.getAutoIncrMapperProcCount(job);  }  public void run(RecordReader<K1, V1> input, OutputCollector<K2, V2> output,                  Reporter reporter)    throws IOException {    try {      // allocate key & value instances that are re-used for all entries      K1 key = input.createKey();      V1 value = input.createValue();            while (input.next(key, value)) {        // map pair to output//迴圈調用map函數        mapper.map(key, value, output, reporter);        if(incrProcCount) {          reporter.incrCounter(SkipBadRecords.COUNTER_GROUP,               SkipBadRecords.COUNTER_MAP_PROCESSED_RECORDS, 1);        }      }    } finally {      mapper.close();    }  }  protected Mapper<K1, V1, K2, V2> getMapper() {    return mapper;  }}


 

要相信,有些時候還是看源碼理解的更快!

 

 

2、shuffle

          shuffle過程其實就是從map的輸出到reduce的輸入過程中所經曆的步驟,堪稱mapreduce的“心臟”,分為3個階段,map端分區、reduce端複製、reduce排序(合并)階段。

 

2.1、map端分區

         由於在mapreduce計算中,有多個map任務和若干個reduce任何,而且各個任務都可能處於不同的機器裡面,所以如何從map任務的輸出到reduce的輸入是一個痛點。

 


        map函數在產生輸出時,並不是簡單的寫到磁碟中,而是利用緩衝的形式寫入到記憶體,並出於效率進行預排序,過程如:

 

 

 

       在寫磁碟之前,線程首先根據reduce的個數將輸出資料劃分成響應的分區(partiton)。在每個分區中,後台線程按鍵進行內排序,如果有個一combiner,它會在排序後的輸出上運行。

 

2.2、reduce端複製階段

    

    由於map任務的輸出檔案寫到了本地磁碟上,並且劃分成reduce個數的分區(每一個reduce需要一個分區),由於map任務完成的時間可能不同,因此只要一個任務完成,reduce任務就開始複製其輸出,這就是reduce任務的複製階段。如所示。

 

2.3、reduce端排序(合并)階段

 

     複製完所有map輸出後,reduce任務進入排序階段(sort phase),這個階段將合并map輸出,維持其順序排序,如所示。

 


3、輸入與輸出格式

       隨著時間的增加,資料的增長也是指數級的增長,且資料的格式也越來越多,對大資料的處理也就越來越困難,為了適應能夠處理各種各樣的資料,hadoop提供了一系列的輸入和輸出格式控制,其目的很簡單,就是能夠解析各種輸入檔案,併產生需要的輸出格式資料


       但是不管處理哪種格式的資料,都要與mapreduce結合起來,才能最大化的發揮hadoop的有點。

    這部分也是hadoop的核心啊!

 

3.1、輸入分區與記錄

 

        在講HDFS的時候,說過,一個輸入分區就是由單個map任務處理的輸入塊一個分區的大小最好與hdfs的塊大小相同

 

        每個分區被劃分成若干個記錄,每個記錄就是一個索引值對,map一個接一個的處理每條記錄


             在資料庫常見中,一個輸入分區可以對應一個表的若干行,而一條記錄對應一行(DBInputFormat)。


 

        輸入分區在hadoop中表示為InputSplit介面,有InputFormat建立的


        InputFormat負責產生輸入分區並將他們分割成記錄,其只是一個介面,具體任務有具體實現去做的

 

 

3.2、FileInputFormat

           FileInputFormat是所有使用檔案作為其資料來源的InputFormat實現的基類,它提供了兩個功能:一個定義哪些檔案包含在作業的輸入中;一個為輸入檔案產生分區的實現。把分區割成基類的作業有其子類實現,FileInputFormat是個抽象類別

 

   FileInputFormat實現了把檔案分區的功能,但它是怎麼來實現了呢?需要先說三個參數:

屬性名稱

類型

預設值

描述

mapred.min.split.size

Int

1

一個檔案分區的最小位元組數

mapred.max.split.size

Long

Long.MAX_VALUE

一個檔案分區的最大位元組數

dfs.block.size

long

64M

HDFS中塊大小

 

   分區的大小有一個公式計算(參考FileInputFomat類的computeSplitSize()方法)


                     max(minimumSize,min(maximumSize,blockSize))


 預設情況下: minimumSize  <  blockSize < maximumSize

 

 

   FileInputFormat只分割大檔案,即檔案大小超過塊大小的檔案


   FileInputFormat產生的InputSplit是一整個檔案(檔案太小,未被分區,整個檔案當成一個分區,供map任務處理)或該檔案的一部分(檔案大,被分區) 

3.3、常用的InputFormat實現

 

 

小檔案與CombineFileInputFormat


      雖然hadoop適合處理大檔案,但在實際的情況中,大量的小檔案處理是少不了的,因此hadoop提供了一個CombineFileInputFormat,它針對小檔案而設計的,它把多個檔案打包到一個分區中一般每個mapper可以處理更多的資料

 

 

TextInputFormat


     hadoop預設的InputFormat,每個記錄的鍵是檔案中行的位移量,值為行內容

 


KeyValueInputFormat


     適合處理設定檔,檔案中行中為key value格式的,如key=value類型的檔案  ,key即為行中的key,value即為行中的value。

 


NLineInputFormat


     也是為處理文字檔而開發的,它的特點是為每個map任務收到固定行數的輸入,其他與TextInputFormat相似。

 


SequenceFileInputFormat(二進位輸入)


     hadoop的循序檔格式儲存格式儲存二進位的索引值對序列,由於循序檔裡面儲存的就是map結構的資料,所以剛好可以有SequenceFileInputFormat 來進行處理。

 


DBInputFormat


     顧名思義,用於使用jdbc從關聯式資料庫中讀取資料。

 

 

多種輸入


        MultipleInputs類可以用來處理多種輸入格式的資料,如輸入資料中包含文本類型和二進位類型的,這個時候就可以用 MultipleInputs來指定某個檔案有哪種輸入類型和哪個map函數來解析。

 

3.4、輸出格式

     既然有輸入格式,就有輸出格式,與輸入格式對應。


     預設的輸出格式是TextOutputFormat,它把記錄寫成文本行,索引值對可以是任意類型, 索引值對中間預設用定位字元分割


 

 

3.5、hadoop特性

 

       除了上面幾點之外,還有計數器、排序、串連等需要關注,詳細待後續吧。。。

 

 


 

大資料時代之hadoop(五):hadoop 分散式運算架構(MapReduce)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.