函数调用分析.docx
- 文档编号:11301805
- 上传时间:2023-02-26
- 格式:DOCX
- 页数:41
- 大小:163.34KB
函数调用分析.docx
《函数调用分析.docx》由会员分享,可在线阅读,更多相关《函数调用分析.docx(41页珍藏版)》请在冰豆网上搜索。
函数调用分析
1引言
1.1致谢
作者是在读了“觉先”的博客《Hadoop学习总结之四:
Map-Reduce的过程解析》之后才从宏观上了解HadoopMapReduce模块的工作原理,并且以此为蓝本,写出了本文。
所以,首先在此向“觉先”表示敬意。
另外本文当中可能有很多地方直接引用前述博文,在此特别声明,后面就不一一标注了。
1.2目的
该文档从源代码的级别剖析了Hadoop0.20.2版本的MapReduce模块的运行原理和流程,对JobTracker、TaskTracker的内部结构和交互流程做了详细介绍。
系统地分析了Map程序和Reduce程序运行的原理。
读者在阅读之后会对HadoopMapReduce0.20.2版本源代码有一个大致的认识。
1.3读者范围
如果读者想只是想从原理上更加深入了解HadoopMapReduce运行机制的话,只需要阅读第2章综述即可,该章节要求读者对HadoopMapReduce模型有系统的了解。
如果读者想深入了解HadoopMapReduce的源代码,则需阅读该文档第2、3节。
阅读第3节需要读者熟练掌握Java语言的基本语法,并且对反射机制、动态代理有一定的了解。
同时,还要求读者对于HadoopHDFS和HadoopRPC的基本用法有一定的了解。
另外,属性Hadoop源代码的最好方法是远程调试,有关远程调试的方法请读者去网上自行查阅资料。
1.4术语定义
Job:
用户所需要完成的工作;
Task:
一个Job可以分解为多个Task,每一个Task都是一个独立的运行单元,多个Task并行运行,从而实现了MapReduce的并行计算。
JobTracker:
在HadoopMapReduce模型中负责Job调度的角色;
TaskTracker:
在HadoopMapReduce模型中负责Task调度的角色;
2综述
Hadoop源代码分为三大模块:
MapReduce、HDFS和HadoopCommon。
其中MapReduce模块主要实现了MapReduce模型的相关功能;HDFS模块主要实现了HDFS的相关功能;而HadoopCommon主要实现了一些基础功能,比如说RPC、网络通信等。
在用户使用HadoopMapReduce模型进行并行计算时,用户只需要写好Map函数、Reduce函数,之后调用JobClient将Job提交即可。
在JobTracker收到提交的Job之后,便会对Job进行一系列的配置,然后交给TaskTracker进行执行。
执行完毕之后,JobTracker会通知JobClient任务完成,并将结果存入HDFS中
如图所示,用户提交Job是通过JobClient类的submitJob()函数实现的。
在Hadoop源代码中,一个被提交了的Job由JobInProgress类的一个实例表示。
该类封装了表示Job的各种信息,以及Job所需要执行的各种动作。
在调用submitJob()函数之后,JobTracker会将作业加入到一个队列中去,这个队列的名字叫做jobInitQueue。
然后,在JobTracker中,有一个名为JobQueueTaskScheduler的对象,会不断轮询jobInitQueue队列,一旦发现有新的Job加入,便将其取出,然后将其初始化。
在Hadoop代码中,一个Task由一个TaskInProgress类的实例表示。
该类封装了描述Task所需的各种信息以及Task执行的各种动作。
TaskTracker自从启动以后,会每隔一段时间向JobTracker发送消息,消息的名称为“Heartbeat”。
Heartbeat中包含了该TaskTracker当前的状态以及对Task的请求。
JobTracker在收到Heartbeat之后,会检查该heartbeat的里所包含的各种信息,如果发现错误会启动相应的错误处理程序。
如果TaskTracker在Heartbeat中添加了对Task的请求,则JobTracker会添加相应的指令在对Heartbeat的回复中。
在Hadoop源代码中,JobTracker对TaskTracker的指令称为action,JobTracker对TaskTracker所发送来的Heartbeat的回复消息称为HeartbeatResponse。
在TaskTracker内部,有一个队列叫做TaskQueue。
该中包含了所有新加入的Task。
每当TaskTracker收到HeartbeatResponse后,会对其进行检查,如果其中包含了新的Task,便将其加入到TaskQueue中。
在TaskTracker内部,有两个线程不断轮询TaskQueue,一个是MapLauncher,另一个是ReduceLauncher。
如果发现有新加入的Map任务,MapLauncher便将其取出并且执行。
如果是Reduce任务,ReduceLauncher便将其取出执行。
不论是MapTask还是ReduceTask,当他们被取出之后,都要进行本地化。
本地化的意思就是将所有需要的信息,比如需要运行的jar文件、配置文件、输入数据等等,一起拷贝到本地的文件系统。
这样做的目的是为了方便任务在某台机器上独立执行。
本地化之后,TaskTracker会为每一个task单独创建一个jvm,然后单独运行。
等Task运行完之后,TaskTracker会通知JobTracker任务完成,以进行下一步的动作。
等到所有的Task都完成之后,Job也就完成了,此时JobTracker会通知JobClient工作完成。
3代码详细分析
下面从用户使用Hadoop进行MapReduce计算的过程为线索,详细介绍Task执行的细节,并对HadoopMapReduce的主要代码进行分析。
3.1启动Hadoop集群
Hadoop集群的启动是通过在Master上运行start-all.sh脚本进行的。
运行该脚本之后,Hadoop会配置一系列的环境变量以及其他Hadoop运行所需要的参数,然后在本机运行JobTracker和NameNode。
然后通过SSH登录到所有slave机器上,启动TaskTracker和DataNode。
因为本文只介绍HadoopMapReduce模块,所以NameNode和DataNode的相关知识不再介绍。
3.2JobTracker启动以及Job的初始化
org.apache.hadoop.mapred.JobTracker类实现了HadoopMapReduce模型的JobTracker的功能,主要负责任务的接受,初始化,调度以及对TaskTracker的监控。
JobTracker单独作为一个JVM运行,main函数就是启动JobTracker的入口函数。
在main函数中,有以下两行非常重要的代码:
startTracker(newJobConf());
JobTracker.offerService();
startTracker函数是一个静态函数,它调用JobTracker的构造函数生成一个JobTracker类的实例,名为result。
然后,进行了一系列初始化活动,包括启动RPCserver,启动内置的jetty服务器,检查是否需要重启JobTracker等。
在JobTracker.offerService()中,调用了taskScheduler对象的start()方法。
该对象是JobTracker的一个数据成员,类型为TaskScheduler。
该类型的提供了一系列接口,使得JobTracker可以对所有提交的job进行初始化以及调度。
但是该类型实际上是一个抽象类型,其真正的实现类型为JobQueueTaskScheduler类,所以,taskScheduler.start()方法执行的是JobQueueTaskScheduler类的start方法。
该方法的详细代码如下:
publicsynchronizedvoidstart()throwsIOException{
//调用TaskScheduler.start()方法,实际上没有做任何事情
super.start();
//注册一个JobInProgressListerner监听器
taskTrackerManager.addJobInProgressListener(jobQueueJobInProgressListener
);
eagerTaskInitializationListener.setTaskTrackerManager(taskTrackerManager);
eagerTaskInitializationListener.start();
taskTrackerManager.addJobInProgressListener(eagerTaskInitializationListener)
}
JobQueueTaskScheduler类的start方法主要注册了两个非常重要的监听器:
jobQueueJobInProgressListener和eagerTaskInitializationListener。
前者是JobQueueJobInProgressListener类的一个实例,该类以先进先出的方式维持一个JobInProgress的队列,并且监听各个JobInProgress实例在生命周期中的变化;后者是EagerTaskInitializationListener类的一个实例,该类不断监听jobInitQueue,一旦发现有新的job被提交(即有新的JobInProgress实例被加入),则立即调用该实例的initTasks方法,对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 List split所在的Node上。 在此,Node代表一个datanode或者机架或者数据中 心。 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);//初始化完毕 …… } 3.3TaskTracker启动以及发送Heartbeat org.apache.hadoop.mapred.TaskTracker类实现了MapReduce模型中TaskTracker的功能。 TaskTracker也是作为一个单独的JVM来运行的,其main函数就是TaskTracker的入口函数,当运行start-all.sh时,脚本就是通过SSH运行该函数来启动TaskTracker的。 Main函数中最重要的语句是: newTaskTracker(conf).run(); 其中run函数主要调用了offerService函数: 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函数的作用就是第2章中提到的向JobTracker发送Heartbeat。 其主要逻辑如下: 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; } 3.4JobTracker接收Heartbeat并向TaskTracker分配任务 当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){ //任务调度器分配
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 函数 调用 分析
![提示](https://static.bdocx.com/images/bang_tan.gif)