mapreduce源碼分析之JobTracker

以下是我研究mapreduce源碼的幾個步驟,其中沒有涉及太多的細節問題,主要就是先將思路理清,爲以後繼續深入研究做點筆記,主要涉及到map和reduce任務的執行步驟,首先從JobTracler的啓動開始,之後到TaskTracker的啓動,TaskTracker通過心跳機制再次回到JobTracker,然後再看JobTracker是怎樣回覆心跳的,然後又會有TaskTracker接受HeartBeatResponse的一系列動作,最後很自然就看到了map和reduce任務是怎樣執行的,最後回到mapreduce包中,mapreduce包中會有一些抽象類以及具體實現的類(在mapreduce.lib中),大概就是這樣一個思路,能理清這樣的思路要感謝豆丁網的一位網友的博文(我再次找的時候已經找不到了)以及“覺先”的博文!

一.JobTracker的啓動

JobTracker裏面裏面有一個main方法,調試時用的,真正應用中在namenode中會啓動該方法,main方法裏面調用兩個方法,分別是StartTrackerOfferSrervice,第一個方法是調用JobTracker的構造函數生成它的對象,並進行一些初始化,包括啓動RPCSERVER,內置的jetty服務器,是否重啓JobTracker等,第二個方法調用了TaskSchedulerstart方法,TaskScheduler是一個抽象類,由JobQueueTaskScheduler具體來實現它,所以真正調用的是JobQueueTaskSchedulerstart方法,下面來分析這個start方法來帶的一系列效應:

該方法主要是註冊了兩個很重要的監聽器,JobQueueJobInProgressListenereagerTaskIntinilionListener,它們都是extendsJobInProgressListener,代碼如下:

----------------------------------------------------------------------------------------------------------------------

@Override

publicsynchronizedvoidstart()throwsIOException{

super.start();

taskTrackerManager.addJobInProgressListener(jobQueueJobInProgressListener);

eagerTaskInitializationListener.setTaskTrackerManager(taskTrackerManager);

eagerTaskInitializationListener.start();

taskTrackerManager.addJobInProgressListener(

eagerTaskInitializationListener);

}

----------------------------------------------------------------------------------------------------------------------

第一個監聽器是以FIFO的方式來維護一個JobInProgress隊列的,並且監聽各個JobInProgress實例的生命週期(之後再好好研究。。。),第二個eagerTaskIntinilionListenerEagerTaskIntinilionListener的一個實例,jobInitQueue主要是在這個類裏面生成,它是一個arraylist,所以EagerTaskIntinilionListener是用來監聽jobInitQueue,一旦有新的job提交,也就是有JobInProgress的實例加入,就會觸發JobInProgress實例的initTask方法,對job進行初始化。這個initTask方法比較複雜,我先按照一條軸線來分析,其他的代碼之後再研究,代碼如下:

----------------------------------------------------------------------------------------------------------------------


publicsynchronizedvoidinitTasks()

throwsIOException,KillInterruptedException{

。。。

。。。

。。。

//readinputsplitsandcreateamapperasplit

//HDFS中讀取job.spilt文件從而生成inputspilts

StringjobFile=profile.getJobFile();


PathsysDir=newPath(this.jobtracker.getSystemDir());

FileSystemfs=sysDir.getFileSystem(conf);

DataInputStream splitFile =

fs.open(newPath(conf.get("mapred.job.split.file")));

JobClient.RawSplit[] splits;

try{

splits =JobClient.readSplitFile(splitFile);

}finally{

splitFile.close();

}

//map的個數就是split的個數

numMapTasks=splits.length;



//ifthenumberofsplitsislargerthanaconfiguredvalue

//thenfailthejob.

intmaxTasks=jobtracker.getMaxTasksPerJob();

if(maxTasks>0&&numMapTasks+numReduceTasks>maxTasks){

thrownewIOException(

"Thenumberoftasksforthisjob"+

(numMapTasks+numReduceTasks)+

"exceedstheconfiguredlimit"+maxTasks);

}

jobtracker.getInstrumentation().addWaiting(

getJobID(),numMapTasks+numReduceTasks);

//爲每一個maptask生成一個TaskInProgress來處理

maps=newTaskInProgress[numMapTasks];

for(inti=0;i<numMapTasks;++i){

inputLength+=splits[i].getDataLength();

maps[i]=newTaskInProgress(jobId,jobFile,

splits[i],

jobtracker,conf,this,i);

}

LOG.info("Inputsizeforjob"+jobId+"="+inputLength

+".Numberofsplits="+splits.length);

if(numMapTasks>0){

nonRunningMapCache=createCache(splits,maxLevel);

}

}

----------------------------------------------------------------------------------------------------------------------


對於maptask,將其放入nonRunningMapCache裏面,他是一個Map<Node,List<TaskInProgress>>,對於maptask 來講,他會被分配到inputsplit所在的Node上,Node在此表示DataNode或者機架或者數據中心,nonRunningMapCache將在JobtrackerTaskTracker分配maptask的時候用到。。。

----------------------------------------------------------------------------------------------------------------------

nonRunningMapCache=createCache(splits,maxLevel);

----------------------------------------------------------------------------------------------------------------------


然後再創建reducetask,放入nonRunningReduces裏面,將在JobtrackerTaskTracker分配reducetask的時候用到。。。

-----------------------------------------------------------------------------------------

this.reduces=newTaskInProgress[numReduceTasks];

for(inti=0;i<numReduceTasks;i++){

reduces[i]=newTaskInProgress(jobId,jobFile,

numMapTasks,i,

jobtracker,conf,this);

nonRunningReduces.add(reduces[i]);

}

-----------------------------------------------------------------------------------------


創建兩個cleanuptask,用來清理mapreduce

-----------------------------------------------------------------------------------------

//create cleanup two cleanup tips, one map and one reduce.

cleanup=newTaskInProgress[2];


//cleanupmaptip.Thismapdoesn'tuseanysplits.Justassignanempty

//split.

JobClient.RawSplitemptySplit=newJobClient.RawSplit();

cleanup[0]=newTaskInProgress(jobId,jobFile,emptySplit,

jobtracker,conf,this,numMapTasks);

cleanup[0].setJobCleanupTask();


//cleanupreducetip.

cleanup[1]=newTaskInProgress(jobId,jobFile,numMapTasks,

numReduceTasks,jobtracker,conf,this);

cleanup[1].setJobCleanupTask();

-----------------------------------------------------------------------------------------


創建兩個初始化task,一個初始化map,一個初始化reduce

-----------------------------------------------------------------------------------------

//create two setup tips, one map and one reduce.

setup=newTaskInProgress[2];


//setupmaptip.Thismapdoesn'tuseanysplit.Justassignanempty

//split.

setup[0]=newTaskInProgress(jobId,jobFile,emptySplit,

jobtracker,conf,this,numMapTasks+1);

setup[0].setJobSetupTask();


//setupreducetip.

setup[1]=newTaskInProgress(jobId,jobFile,numMapTasks,

numReduceTasks+1,jobtracker,conf,this);

setup[1].setJobSetupTask();


最後看到tasksInited.set(true)方法,說明初始化完成,其他方法之後再看。

----------------------------------------------------------------------------------------------------------------------

synchronized(jobInitKillStatus){

jobInitKillStatus.initDone=true;

if(jobInitKillStatus.killed){

thrownewKillInterruptedException("Job"+jobId+"killedininit");

}

}

tasksInited.set(true);

JobHistory.JobInfo.logInited(profile.getJobID(),this.launchTime,

numMapTasks,numReduceTasks);


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