Hadoop学习总结之四MapReduce的过程解析.docx

上传人:b****5 文档编号:30210685 上传时间:2023-08-07 格式:DOCX 页数:33 大小:178.26KB
下载 相关 举报
Hadoop学习总结之四MapReduce的过程解析.docx_第1页
第1页 / 共33页
Hadoop学习总结之四MapReduce的过程解析.docx_第2页
第2页 / 共33页
Hadoop学习总结之四MapReduce的过程解析.docx_第3页
第3页 / 共33页
Hadoop学习总结之四MapReduce的过程解析.docx_第4页
第4页 / 共33页
Hadoop学习总结之四MapReduce的过程解析.docx_第5页
第5页 / 共33页
点击查看更多>>
下载资源
资源描述

Hadoop学习总结之四MapReduce的过程解析.docx

《Hadoop学习总结之四MapReduce的过程解析.docx》由会员分享,可在线阅读,更多相关《Hadoop学习总结之四MapReduce的过程解析.docx(33页珍藏版)》请在冰豆网上搜索。

Hadoop学习总结之四MapReduce的过程解析.docx

Hadoop学习总结之四MapReduce的过程解析

一、客户端

Map-Reduce的过程首先是由客户端提交一个任务开始的。

提交任务主要是通过JobClient.runJob(JobConf)静态函数实现的:

publicstaticRunningJobrunJob(JobConfjob)throwsIOException{

 //首先生成一个JobClient对象

 JobClientjc=newJobClient(job);

 ……

 //调用submitJob来提交一个任务

 running=jc.submitJob(job);

 JobIDjobId=running.getID();

 ……

 while(true){

    //while循环中不断得到此任务的状态,并打印到客户端console中

 }

 returnrunning;

}

其中JobClient的submitJob函数实现如下:

publicRunningJobsubmitJob(JobConfjob)throwsFileNotFoundException,

                               InvalidJobConfException,IOException{

 //从JobTracker得到当前任务的id

 JobIDjobId=jobSubmitClient.getNewJobId();

 //准备将任务运行所需要的要素写入HDFS:

 //任务运行程序所在的jar封装成job.jar

 //任务所要处理的inputsplit信息写入job.split

 //任务运行的配置项汇总写入job.xml

 PathsubmitJobDir=newPath(getSystemDir(),jobId.toString());

 PathsubmitJarFile=newPath(submitJobDir,"job.jar");

 PathsubmitSplitFile=newPath(submitJobDir,"job.split");

 //此处将-libjars命令行指定的jar上传至HDFS

 configureCommandLineOptions(job,submitJobDir,submitJarFile);

 PathsubmitJobFile=newPath(submitJobDir,"job.xml");

 ……

 //通过inputformat的格式获得相应的inputsplit,默认类型为FileSplit

 InputSplit[]splits=

   job.getInputFormat().getSplits(job,job.getNumMapTasks());

 

 //生成一个写入流,将inputsplit得信息写入job.split文件

 FSDataOutputStreamout=FileSystem.create(fs,

     submitSplitFile,newFsPermission(JOB_FILE_PERMISSION));

 try{

   //写入job.split文件的信息包括:

split文件头,split文件版本号,split的个数,接着依次写入每一个inputsplit的信息。

   //对于每一个inputsplit写入:

split类型名(默认FileSplit),split的大小,split的内容(对于FileSplit,写入文件名,此split在文件中的起始位置),split的location信息(即在那个DataNode上)。

   writeSplitsFile(splits,out);

 }finally{

   out.close();

 }

 job.set("mapred.job.split.file",submitSplitFile.toString());

 //根据split的个数设定maptask的个数

 job.setNumMapTasks(splits.length);

 //写入job的配置信息入job.xml文件      

 out=FileSystem.create(fs,submitJobFile,

     newFsPermission(JOB_FILE_PERMISSION));

 try{

   job.writeXml(out);

 }finally{

   out.close();

 }

 //真正的调用JobTracker来提交任务

 JobStatusstatus=jobSubmitClient.submitJob(jobId);

 ……

}

 

二、JobTracker

JobTracker作为一个单独的JVM运行,其运行的main函数主要调用有下面两部分:

∙调用静态函数startTracker(newJobConf())创建一个JobTracker对象

∙调用JobTracker.offerService()函数提供服务

在JobTracker的构造函数中,会生成一个taskScheduler成员变量,来进行Job的调度,默认为JobQueueTaskScheduler,也即按照FIFO的方式调度任务。

在offerService函数中,则调用taskScheduler.start(),在这个函数中,为JobTracker(也即taskScheduler的taskTrackerManager)注册了两个Listener:

∙JobQueueJobInProgressListenerjobQueueJobInProgressListener用于监控job的运行状态

∙EagerTaskInitializationListenereagerTaskInitializationListener用于对Job进行初始化

EagerTaskInitializationListener中有一个线程JobInitThread,不断得到jobInitQueue中的JobInProgress对象,调用JobInProgress对象的initTasks函数对任务进行初始化操作。

在上一节中,客户端调用了JobTracker.submitJob函数,此函数首先生成一个JobInProgress对象,然后调用addJob函数,其中有如下的逻辑:

synchronized(jobs){

 synchronized(taskScheduler){

   jobs.put(job.getProfile().getJobID(),job);

   //对JobTracker的每一个listener都调用jobAdded函数

   for(JobInProgressListenerlistener:

jobInProgressListeners){

     listener.jobAdded(job);

   }

 }

}

 

EagerTaskInitializationListener的jobAdded函数就是向jobInitQueue中添加一个JobInProgress对象,于是自然触发了此Job的初始化操作,由JobInProgress得initTasks函数完成:

publicsynchronizedvoidinitTasks()throwsIOException{

 ……

 //从HDFS中读取job.split文件从而生成inputsplits

 StringjobFile=profile.getJobFile();

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

 FileSystemfs=sysDir.getFileSystem(conf);

 DataInputStreamsplitFile=

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

 JobClient.RawSplit[]splits;

 try{

   splits=JobClient.readSplitFile(splitFile);

 }finally{

   splitFile.close();

 }

 //maptask的个数就是inputsplit的个数

 numMapTasks=splits.length;

 //为每个maptasks生成一个TaskInProgress来处理一个inputsplit

 maps=newTaskInProgress[numMapTasks];

 for(inti=0;i

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

   maps[i]=newTaskInProgress(jobId,jobFile,

                                splits[i],

                                jobtracker,conf,this,i);

 }

 //对于maptask,将其放入nonRunningMapCache,是一个Map>,也即对于maptask来讲,其将会被分配到其inputsplit所在的Node上。

nonRunningMapCache将在JobTracker向TaskTracker分配maptask的时候使用。

 if(numMapTasks>0){

   nonRunningMapCache=createCache(splits,maxLevel);

 }

 

 //创建reducetask

 this.reduces=newTaskInProgress[numReduceTasks];

 for(inti=0;i

   reduces[i]=newTaskInProgress(jobId,jobFile,

                                   numMapTasks,i,

                                   jobtracker,conf,this);

   //reducetask放入nonRunningReduces,其将在JobTracker向TaskTracker分配reducetask的时候使用。

   nonRunningReduces.add(reduces[i]);

 }

 

 //创建两个cleanuptask,一个用来清理map,一个用来清理reduce.

 cleanup=newTaskInProgress[2];

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

         jobtracker,conf,this,numMapTasks);

 cleanup[0].setJobCleanupTask();

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

                    numReduceTasks,jobtracker,conf,this);

 cleanup[1].setJobCleanupTask();

 //创建两个初始化task,一个初始化map,一个初始化reduce.

 setup=newTaskInProgress[2];

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

         jobtracker,conf,this,numMapTasks+1);

 setup[0].setJobSetupTask();

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

                    numReduceTasks+1,jobtracker,conf,this);

 setup[1].setJobSetupTask();

 tasksInited.set(true);//初始化完毕

 ……

}

 

三、TaskTracker

TaskTracker也是作为一个单独的JVM来运行的,在其main函数中,主要是调用了newTaskTracker(conf).run(),其中run函数主要调用了:

StateofferService()throwsException{

 longlastHeartbeat=0;

 //TaskTracker进行是一直存在的

 while(running&&!

shuttingDown){

     ……

     longnow=System.currentTimeMillis();

     //每隔一段时间就向JobTracker发送heartbeat

     longwaitTime=heartbeatInterval-(now-lastHeartbeat);

     if(waitTime>0){

       synchronized(finishedCount){

         if(finishedCount[0]==0){

           finishedCount.wait(waitTime);

         }

         finishedCount[0]=0;

       }

     }

     ……

     //发送Heartbeat到JobTracker,得到response

     HeartbeatResponseheartbeatResponse=transmitHeartBeat(now);

     ……

    //从Response中得到此TaskTracker需要做的事情

     TaskTrackerAction[]actions=heartbeatResponse.getActions();

     ……

     if(actions!

=null){

       for(TaskTrackerActionaction:

actions){

         if(actioninstanceofLaunchTaskAction){

           //如果是运行一个新的Task,则将Action添加到任务队列中

           addToTaskQueue((LaunchTaskAction)action);

         }elseif(actioninstanceofCommitTaskAction){

           CommitTaskActioncommitAction=(CommitTaskAction)action;

           if(!

commitResponses.contains(commitAction.getTaskID())){

             commitResponses.add(commitAction.getTaskID());

           }

         }else{

           tasksToCleanup.put(action);

         }

       }

     }

 }

 returnState.NORMAL;

}

其中transmitHeartBeat主要逻辑如下:

privateHeartbeatResponsetransmitHeartBeat(longnow)throwsIOException{

 //每隔一段时间,在heartbeat中要返回给JobTracker一些统计信息

 booleansendCounters;

 if(now>(previousUpdate+COUNTER_UPDATE_INTERVAL)){

   sendCounters=true;

   previousUpdate=now;

 }

 else{

   sendCounters=false;

 }

 ……

 //报告给JobTracker,此TaskTracker的当前状态

 if(status==null){

   synchronized(this){

     status=newTaskTrackerStatus(taskTrackerName,localHostname,

                                    httpPort,

                                    cloneAndResetRunningTaskStatuses(

                                      sendCounters),

                                    failures,

                                    maxCurrentMapTasks,

                                    maxCurrentReduceTasks);

   }

 }

 ……

 //当满足下面的条件的时候,此TaskTracker请求JobTracker为其分配一个新的Task来运行:

 //当前TaskTracker正在运行的maptask的个数小于可以运行的maptask的最大个数

 //当前TaskTracker正在运行的reducetask的个数小于可以运行的reducetask的最大个数

 booleanaskForNewTask;

 longlocalMinSpaceStart;

 synchronized(this){

   askForNewTask=(status.countMapTasks()

                    status.countReduceTasks()

                   acceptNewTasks;

   localMinSpaceStart=minSpaceStart;

 }

 ……

 //向JobTracker发送heartbeat,这是一个RPC调用

 HeartbeatResponseheartbeatResponse=jobClient.heartbeat(status,

                                                           justStarted,askForNewTask,

                                                           heartbeatResponseId);

 ……

 returnheartbeatResponse;

}

 

四、JobTracker

当JobTracker被RPC调用来发送heartbeat的时候,JobTracker的heartbeat(TaskTrackerStatusstatus,booleaninitialContact,booleanacceptNewTasks,shortresponseId)函数被调用:

publicsynchronizedHeartbeatResponseheartbeat(TaskTrackerStatusstatus,

                                               booleaninitialContact,booleanacceptNewTasks,shortresponseId)

 throwsIOException{

 ……

 StringtrackerName=status.getTrackerName();

 ……

 shortnewResponseId=(short)(responseId+1);

 ……

 HeartbeatResponseresponse=newHeartbeatResponse(newResponseId,null);

 Listactions=newArrayList();

 //如果TaskTracker向JobTracker请求一个task运行

 if(acceptNewTasks){

   TaskTrackerStatustaskTrackerStatus=getTaskTracker(trackerName);

   if(taskTrackerStatus==null){

     LOG.warn("Unknowntasktrackerpolling;ignoring:

"+trackerName);

   }else{

     //setup和cleanup的task优先级最高

     Listtasks=getSetupAndCleanupTasks(taskTrackerStatus);

     if(tasks==null){

       //任务调度器分配任务

       tasks=taskScheduler.assignTasks(task

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 工学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1