mapreduce源码分析之JobTracker

来源:互联网 发布:网络中央电视台 编辑:程序博客网 时间:2024/05/16 19:23

以下是我研究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);