MapReduce工作的基本流程

     Hadoop0.2之前版本和之後版本在Job中有很大的改進,本次採用的版本是Hadoop1.1.2版本。

     現在作爲作業驅動器,可以直接繼承Configured以及實現Tool,這種方式可以很便捷的獲取啓動時候命令行中輸入的作業配置參數,常規的Job啓動如下:


public class SortByHash extends Configured implements Tool
{
   public int run(String[] args) throws Exception {
    //這裏面負責配置job屬性
        Configuration conf=getConf();
        String[] paths=new GenericOptionsParser(conf, args).getRemainingArgs();
        String tradeDir=paths[0];
        String payDir=paths[1];
    String joinDir=paths[2];
    Job job=new Job(conf,"JoinJob");
    job.setJarByClass(JoinMain.class);
    FileInputFormat.addInputPath(job, new Path(tradeDir));
    FileInputFormat.addInputPath(job, new Path(payDir));
    FileOutputFormat.setOutputPath(job, new Path(joinDir));
                                                                                                                                                          
    job.setMapperClass(JoinMapper.class);
    job.setReducerClass(JoinReducer.class);
    job.setMapOutputKeyClass(TextIntPair.class);
    job.setMapOutputValueClass(Text.class);
    job.setOutputKeyClass(Text.class);
    job.setOutputValueClass(Text.class);
    job.waitForCompletion(true);
    int exitCode=job.isSuccessful()?0:1;
    return exitCode;
   }
   public static void main(String[] args) throws Exception
   {
      // TODO Auto-generated method stub
      int exitCode=ToolRunner.run(new SortByHashPartitioner(), args);
      System.exit(exitCode);
   }
}


由於Tool的所有實現都需要實現Configurable,Configured又是Configurable的具體實現,所以要同時繼承Configured和實現Tool,這樣就不需要實現Tool中定義的所有方法了。利用Tool接口來跑MapReduce,可以在命令行中設置一些參數,比硬編碼好很多。

      注意利用Tool啓動作業基本方式如下:ToolRunner首先調用自己的靜態方法run,在該方法中會首先創建一個Configurable對象。然後調用GenericOptionsParser解析命令行參數,並設置給剛創建的Configurable對象。然後再次設置主類(這裏即SortByHashPartitioner)setConf方法,最後調用主類的run方法執行。所以在run中要想使用命令行參數必須如下:

       Configurationconf = getConf();

       Jobjob = newJob(conf);

       hadoop0.2之後的作業啓動是調用job.waitForCompletion(true);的;然後就會進行作業的提交、執行、完成等操作

調用waitForCompletion具體的工作流:

第一,調用submit提交作業

第二,當參數爲true的時候,調用monitorAndPrintJob來進行監聽作業的進度。

作業提交即submit():

第一,打開一個JobTracker的連接,這裏會創建一個JobClient對象

jobClient= new JobClient((JobConf) getConfiguration());

這裏的Configuration在初始化創建job的時候就會主動創建的

第二,根據創建的JobClient來調用submitJobInternal()提交作業給系統。

這裏會對於命令行中的選項進行檢查

1)獲取一個作業編號JobIDjobSubmitClient.getNewJobId()jobSubmitclient是一個JobSubmissionProtocolJobTracker就是這個類的子類,JobClient創建的時候就會new一個

2)獲取目錄的代理,將運行作業需要的資源jar文件,配置文件都複製到一個以作業ID命名的目錄下JobTracker文件系統中。

3)檢查作業的輸出說明。如果沒有指定的輸出目錄或者輸出目錄已經不存在,則不提交,返回錯誤

4)創建作業的輸入分片。如果分片無法計算,如輸入路徑不存在,則不提交,報告錯誤。

5)將該作業寫入作業隊列中,然後將該文件寫入JobTracker的文件系統中

6)所有都通過後,真正的提交作業,調用submitJob()告知JobTracker準備執行作業.

作業初始化

JobTracker接受到submitJob()調用後,會將此調用放入內部隊列中queue,交由作業調度器(JobScheduler)進行調度,並對其進行初始化操作。

初始化主要是由作業調度器完成的,創建一個任務運行列表。作業調度器會首先從共享文件系統中獲取JobClient已經計算好的分片信息,然後爲每一個分片創建一個Map任務,創建的reduce數量由mapred.reduce.task來決定,一般是通過setNumReduceTask()設定的。

任務的分配

tasktracker會定期的向jobtracker發送一個心跳告訴是否存活,也是兩個之間的通信通道。這裏發送心跳的目的就是利用心跳來告知jobtrackertasktracker還活着,會指明自己是否已經準備好運行新的任務,如果是,則jobtracker會爲它分配一個任務。這裏的tasktracker就利用週期性的循環來向jobtracker來“拉活”。

每一個tasktracker有固定的map任務槽和reduce任務槽。

選擇一個map任務,jobtracker會考慮tasktracker的網絡位置,並且選擇一個距離其輸入分片最近的tasktracker。一般都遵循數據本地化或機架本地化。

選擇一個reduce任務,jobtracker簡單地從待運行的reduce任務列表中選取下一個來執行,不許要考慮數據的本地化。

任務的執行

tasktracker初次被分配了一個任務後,就開始要運行該任務。

第一步,從共享文件系統將作業的JAR文件複製到tasktracker所在的文件系統,目的就是實現了作業的JAR文件本地化。並且將應用程序所需要的全部文件從分佈式緩存中複製到本地磁盤。

第二步,tasktracker爲分配的任務創建一個本地工作目錄,將JAR文件內容解壓到這個文件夾

第三步,tasktracker創建一個TaskRunner實例來運行該任務。TaskRunner啓動一個新的JVM來運行每個任務。

任務進度的更新

monitorAndPrintJob(),這個方法就是實時的報告作業的運行情況,以打印在控制檯上。這個會每隔1秒進行查看,利用的就是Thread.sleep(1000)來執行的。

如果任務報告了進度,則會設置一個標誌來表明任務狀態發生了變化。在tasktracker中,除了運行任務的線程外,還有個獨立的線程每隔3秒會檢測任務的狀態,如果已經設置,則告知tasktracker當前任務狀態。而tasktracker每隔5秒會發送心跳到jobtracker,這裏發送心跳的目的主要是報告tasktracker上運行的所有任務的狀態。

作業的完成

jobtracker收到作業的最後一個任務已經完成的通知後,則就會把作業的狀態設置爲“成功”。此時JobClient會打印一條消息告知用戶作業已經完成了。Jobtrackertasktracker都會清空作業的工作狀態。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章