Hadoop学习总结之四MapReduce的过程解析.docx
- 文档编号:30210685
- 上传时间:2023-08-07
- 格式:DOCX
- 页数:33
- 大小:178.26KB
Hadoop学习总结之四MapReduce的过程解析.docx
《Hadoop学习总结之四MapReduce的过程解析.docx》由会员分享,可在线阅读,更多相关《Hadoop学习总结之四MapReduce的过程解析.docx(33页珍藏版)》请在冰豆网上搜索。
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 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); List //如果TaskTracker向JobTracker请求一个task运行 if(acceptNewTasks){ TaskTrackerStatustaskTrackerStatus=getTaskTracker(trackerName); if(taskTrackerStatus==null){ LOG.warn("Unknowntasktrackerpolling;ignoring: "+trackerName); }else{ //setup和cleanup的task优先级最高 List if(tasks==null){ //任务调度器分配任务 tasks=taskScheduler.assignTasks(task
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Hadoop 学习 总结 MapReduce 过程 解析
![提示](https://static.bdocx.com/images/bang_tan.gif)