转自:http://blog.csdn.net/Androidlushangderen/article/details/41408517

JobTracker的作业调度给我感觉就是比较宏观意义上的操作。倘若你只了解了MapReduce的工作原理是远远不够的,这时去学习一下他在宏观层面的原理实现也是对我们非常有帮助的。首先我们又得从上次分析的任务提交之后的操作说起,Job作业通过RPC通信提交到JobTracker端之后,接下来会触发到下面的方法;

  1. /**
  2. * 初始化作业操作
  3. */
  4. public void initJob(JobInProgress job) {
  5. if (null == job) {
  6. LOG.info("Init on null job is not valid");
  7. return;
  8. }
  9. try {
  10. JobStatus prevStatus = (JobStatus)job.getStatus().clone();
  11. LOG.info("Initializing " + job.getJobID());
  12. //初始化Task任务
  13. job.initTasks();
  14. ......

接着会执行initTasks的方法,但不是JobTracker,而是JobInProgress类中的方法:

  1. /**
  2. * Construct the splits, etc.  This is invoked from an async
  3. * thread so that split-computation doesn't block anyone.
  4. */
  5. public synchronized void initTasks()
  6. throws IOException, KillInterruptedException, UnknownHostException {
  7. if (tasksInited || isComplete()) {
  8. return;
  9. }
  10. ......
  11. jobtracker.getInstrumentation().addWaitingMaps(getJobID(), numMapTasks);
  12. jobtracker.getInstrumentation().addWaitingReduces(getJobID(), numReduceTasks);
  13. this.queueMetrics.addWaitingMaps(getJobID(), numMapTasks);
  14. this.queueMetrics.addWaitingReduces(getJobID(), numReduceTasks);
  15. //根据numMapTasks任务数,创建MapTask的总数
  16. maps = new TaskInProgress[numMapTasks];
  17. for(int i=0; i < numMapTasks; ++i) {
  18. inputLength += splits[i].getInputDataLength();
  19. maps[i] = new TaskInProgress(jobId, jobFile,
  20. splits[i],
  21. jobtracker, conf, this, i, numSlotsPerMap);
  22. }
  23. ......
  24. //
  25. // Create reduce tasks
  26. //根据numReduceTasks,创建Reduce的Task数量
  27. this.reduces = new TaskInProgress[numReduceTasks];
  28. for (int i = 0; i < numReduceTasks; i++) {
  29. reduces[i] = new TaskInProgress(jobId, jobFile,
  30. numMapTasks, i,
  31. jobtracker, conf, this, numSlotsPerReduce);
  32. nonRunningReduces.add(reduces[i]);
  33. }
  34. ......
  35. // create cleanup two cleanup tips, one map and one reduce.
  36. //创建2个clean up Task任务,1个是Map Clean-Up Task,一个是Reduce Clean-Up Task
  37. cleanup = new TaskInProgress[2];
  38. // cleanup map tip. This map doesn't use any splits. Just assign an empty
  39. // split.
  40. TaskSplitMetaInfo emptySplit = JobSplit.EMPTY_TASK_SPLIT;
  41. cleanup[0] = new TaskInProgress(jobId, jobFile, emptySplit,
  42. jobtracker, conf, this, numMapTasks, 1);
  43. cleanup[0].setJobCleanupTask();
  44. // cleanup reduce tip.
  45. cleanup[1] = new TaskInProgress(jobId, jobFile, numMapTasks,
  46. numReduceTasks, jobtracker, conf, this, 1);
  47. cleanup[1].setJobCleanupTask();
  48. // create two setup tips, one map and one reduce.
  49. //原理同上
  50. setup = new TaskInProgress[2];
  51. // setup map tip. This map doesn't use any split. Just assign an empty
  52. // split.
  53. setup[0] = new TaskInProgress(jobId, jobFile, emptySplit,
  54. jobtracker, conf, this, numMapTasks + 1, 1);
  55. setup[0].setJobSetupTask();
  56. // setup reduce tip.
  57. setup[1] = new TaskInProgress(jobId, jobFile, numMapTasks,
  58. numReduceTasks + 1, jobtracker, conf, this, 1);
  59. setup[1].setJobSetupTask();
  60. ......

可以看见,在这里JobInProgress首次被划分为了很多的小的Task任务的形式存在,而这些小的任务是以TaskInProgress的类表示。在这里MapReduce把1个作业做出了如下的分解,numMapTasks个Map Task ,numReduceTasks个Reduce Task,2个CleanUp任务,2个SetUp任务,(Map Reduce,每个各占1个),好,可以大致勾画一下,1个JobInProgress的执行流程了。

ok,initTask的任务已经完成,也就是说前面初始化的准备工作都已经完成了,后面就等着JobTacker分配作业给TaskTracker了。在这里MapReduce用的是HeartBeat的形式,就是心跳机制,心跳包在这里主要有3个作用:

1.判断TaskTracker是否活着

2.获取各个TaskTracker上的资源使用情况和任务的进度

3.给TaskTracker分配任务

而这里用到的就是第三作用。HeartBeat的调用形式同样是Hadoop自带的RPC实现方式。JobTracker不会直接分配作业给TaskTracker,中间会经过一个叫TaskScheduler掉调度器,这个可以用户自定义实现,满足不同的需求设计,在Hadoop中有默认的实现,所以你会看到大致这样的一个模型流程:

所以接下来JobTracker首先会收到很多来自TaskTracker的心跳包,判断此TaskTracker是否是无任务状态的,无任务的话,马上让TaskSchedulera分配任务给他:

  1. public synchronized HeartbeatResponse heartbeat(TaskTrackerStatus status,
  2. boolean restarted,
  3. boolean initialContact,
  4. boolean acceptNewTasks,
  5. short responseId)
  6. throws IOException {
  7. ....
  8. //通过心跳机制发送命令回应
  9. // Initialize the response to be sent for the heartbeat
  10. HeartbeatResponse response = new HeartbeatResponse(newResponseId, null);
  11. List<TaskTrackerAction> actions = new ArrayList<TaskTrackerAction>();
  12. boolean isBlacklisted = faultyTrackers.isBlacklisted(status.getHost());
  13. // Check for new tasks to be executed on the tasktracker
  14. if (recoveryManager.shouldSchedule() && acceptNewTasks && !isBlacklisted) {
  15. TaskTrackerStatus taskTrackerStatus = getTaskTrackerStatus(trackerName);
  16. if (taskTrackerStatus == null) {
  17. LOG.warn("Unknown task tracker polling; ignoring: " + trackerName);
  18. } else {
  19. List<Task> tasks = getSetupAndCleanupTasks(taskTrackerStatus);
  20. //说明此TaskTtracker上无任务了
  21. if (tasks == null ) {
  22. //为此TaskTracker分配任务
  23. tasks = taskScheduler.assignTasks(taskTrackers.get(trackerName));
  24. }

接下来就是TaskScheduler的方法了,不过得找出他的实现类,TaskScheduler只是一个基类:

  1. public synchronized List<Task> assignTasks(TaskTracker taskTracker)
  2. throws IOException {
  3. TaskTrackerStatus taskTrackerStatus = taskTracker.getStatus();
  4. ClusterStatus clusterStatus = taskTrackerManager.getClusterStatus();
  5. final int numTaskTrackers = clusterStatus.getTaskTrackers();
  6. final int clusterMapCapacity = clusterStatus.getMaxMapTasks();
  7. final int clusterReduceCapacity = clusterStatus.getMaxReduceTasks();
  8. //获取作业队列
  9. Collection<JobInProgress> jobQueue =
  10. jobQueueJobInProgressListener.getJobQueue();
  11. .....
  12. for (JobInProgress job : jobQueue) {
  13. if (job.getStatus().getRunState() != JobStatus.RUNNING ||
  14. job.numReduceTasks == 0) {
  15. continue;
  16. }
  17. //在这里分配了一个新的Reduce任务
  18. Task t =
  19. job.obtainNewReduceTask(taskTrackerStatus, numTaskTrackers,
  20. taskTrackerManager.getNumberOfUniqueHosts()
  21. );
  22. .....

首先获取一个作业列表,在里面挑出一个作业给,在比如从里面挑出1个Reduce的任务区给整个TaskTracker执行,因为我们刚刚已经知道,所有的Task都是以TaskInProgress形式被包含于JobInProgress中的,所以又来到了JobInProgress中了

  1. /**
  2. * Return a ReduceTask, if appropriate, to run on the given tasktracker.
  3. * We don't have cache-sensitivity for reduce tasks, as they
  4. *  work on temporary MapRed files.
  5. */
  6. public synchronized Task obtainNewReduceTask(TaskTrackerStatus tts,
  7. int clusterSize,
  8. int numUniqueHosts
  9. ) throws IOException {
  10. .....
  11. int  target = findNewReduceTask(tts, clusterSize, numUniqueHosts,
  12. status.reduceProgress());
  13. if (target == -1) {
  14. return null;
  15. }
  16. //这里继续调用方法,获取目标任务
  17. Task result = reduces[target].getTaskToRun(tts.getTrackerName());
  18. if (result != null) {
  19. addRunningTaskToTIP(reduces[target], result.getTaskID(), tts, true);
  20. }
  21. return result;
  22. }

此时就执行了一个TIP就是TaskInProgress里面去执行了,此时的转变就是JIP->TIP的转变。继续往里看,这时候来到的是TaskInProgress的类里面了:

  1. public Task getTaskToRun(String taskTracker) throws IOException {
  2. if (0 == execStartTime){
  3. // assume task starts running now
  4. execStartTime = jobtracker.getClock().getTime();
  5. }
  6. // Create the 'taskid'; do not count the 'killed' tasks against the job!
  7. TaskAttemptID taskid = null;
  8. if (nextTaskId < (MAX_TASK_EXECS + maxTaskAttempts + numKilledTasks)) {
  9. // Make sure that the attempts are unqiue across restarts
  10. int attemptId = job.getNumRestarts() * NUM_ATTEMPTS_PER_RESTART + nextTaskId;
  11. //启动一次TA尝试
  12. taskid = new TaskAttemptID( id, attemptId);
  13. ++nextTaskId;
  14. } else {
  15. LOG.warn("Exceeded limit of " + (MAX_TASK_EXECS + maxTaskAttempts) +
  16. " (plus " + numKilledTasks + " killed)"  +
  17. " attempts for the tip '" + getTIPId() + "'");
  18. return null;
  19. }
  20. //加入到相应的数据结构中
  21. return addRunningTask(taskid, taskTracker);
  22. }

在这里明显的执行了所谓的TA尝试,就是说这是一次Task的尝试执行,因为不能保证这次任务就一定能执行成功。把这次尝试的任务ID加入系统变量中,就来到了addRunningTask,也就是说来到了方法执行的最末尾:

  1. /**
  2. * Adds a previously running task to this tip. This is used in case of
  3. * jobtracker restarts.
  4. * 添加任务
  5. */
  6. public Task addRunningTask(TaskAttemptID taskid,
  7. String taskTracker,
  8. boolean taskCleanup) {
  9. .....
  10. //添加任务和taskTracker的映射关系
  11. activeTasks.put(taskid, taskTracker);
  12. tasks.add(taskid);
  13. // Ask JobTracker to note that the task exists
  14. //在JobTracker中增加一对任务记录
  15. jobtracker.createTaskEntry(taskid, taskTracker, this);
  16. // check and set the first attempt
  17. if (firstTaskId == null) {
  18. firstTaskId = taskid;
  19. }
  20. return t;
  21. }

在这里,就增加了任务和TaskTracker的一些任务运行信息的变量关系。后面就等着TaskTracker自己去把任务挑出来,执行就OK了,上面这个步骤从TIP->TA的转变。我们把这种结构流程叫做“三层多叉树”的方式结构。

整个作业的调度的时序关系图如下:

JobTracker作业调度分析的更多相关文章

  1. Hadoop学习之--Fair Scheduler作业调度分析

    Fair Scheduler调度器同步心跳分配任务的过程简单来讲会经历以下环节: 1. 对map/reduce是否已经达到资源上限的循环判断 2. 对pool队列根据Fair算法排序 3.然后循环po ...

  2. 大数据基础Hadoop 2.x入门

    hadoop概述 存储和分析网络数据 三大组件 MapReduce 对海量数据的处理 思想: 分而治之 每个数据集进行逻辑业务处理map 合并统计数据结果reduce HDFS 储存海量数据 分布式存 ...

  3. hadoop运行原理之Job运行(四) JobTracker端心跳机制分析

    接着上篇来说,TaskTracker端的transmitHeartBeat()方法通过RPC调用JobTracker端的heartbeat()方法来接收心跳并返回心跳应答.还是先看看这张图,对它的大概 ...

  4. 监听器初始化Job、JobTracker相应TaskTracker心跳、调度器分配task源码级分析

    JobTracker和TaskTracker分别启动之后(JobTracker启动流程源码级分析,TaskTracker启动过程源码级分析),taskTracker会通过心跳与JobTracker通信 ...

  5. MapReduce job在JobTracker初始化源码级分析

    mapreduce job提交流程源码级分析(三)中已经说明用户最终调用JobTracker.submitJob方法来向JobTracker提交作业.而这个方法的核心提交方法是JobTracker.a ...

  6. 【Flink】Flink作业调度流程分析

    1. 概述 当向Flink集群提交用户作业时,从用户角度看,只需要作业处理逻辑正确,输出正确的结果即可:而不用关心作业何时被调度的,作业申请的资源又是如何被分配的以及作业何时会结束:但是了解作业在运行 ...

  7. JobTracker启动流程源码级分析

    org.apache.hadoop.mapred.JobTracker类是个独立的进程,有自己的main函数.JobTracker是在网络环境中提交及运行MR任务的核心位置. main方法主要代码有两 ...

  8. Elastic-Job-Lite分析——作业调度器 JobScheduler 的创建过程

    -----------------------------------1. 创建注册中心的对象----------------------------------------------------- ...

  9. hadoop运行原理之Job运行(一) JobTracker启动及初始化

    这部分的计划是这样的,首先解释JobTracker的启动过程和作业从JobClient提交到JobTracker上:然后分析TaskTracker和heartbeat:最后将整个流程debug一遍来加 ...

随机推荐

  1. xcode arc 下使用 block警告 Capturing [an object] strongly in this block is likely to lead to a retain cycle” in ARC-enabled code

    xcode arc 下使用 block警告 Capturing [an object] strongly in this block is likely to lead to a retain cyc ...

  2. Android 微信支付,授权,分享回调区分记录

    我们做项目中避免不了和微信打交道,其中最常用的也就是授权登录与分享和支付了. 本篇文章记录这三个功能同时使用的时候,回调怎么来区分.因为每个功能都有自己的回调状态.前期集成与发送,资料很多了就不在这里 ...

  3. MMORPG 游戏服务器端设计

    http://www.oschina.net/question/12_22983 这里给出一种宏观把握MMORPG服务器设计的文章,适合入门,读完后对服务器端的设计能有大概的掌握,方便对感兴趣的部分进 ...

  4. Android 查看 无wifi/usb设备的logcat方法

    Android 查看 无wifi/usb设备的logcat方法 一.情况 一个定制Android设备,wifi被去掉.我须要调试一个USB设备这样也无法用usb来输出logcat. 由于这个USB设备 ...

  5. 【VBA编程】07.循环结构语句

    [FOR...NEXT语句] For counter = start To End [Step step] [statements] [Exit For] [statements] Next [cou ...

  6. mybatis加入条件

    根据http://www.cnblogs.com/friends-wf/p/3799315.html搭建的环境 User.xml加入的 if where判断的 <!-- 根据条件查询一个用户 - ...

  7. javascript中call apply的区别

    obj.call(thisObj, arg1, arg2, ...); obj.apply(thisObj, [arg1, arg2, ...]); 两者作用一致,都是把obj(即this)绑定到th ...

  8. 【转载】Java 日常开发 - 常见异常

    转自 http://blog.sina.com.cn/s/blog_ab345e5d01010zaq.html 算术异常类:ArithmeticExecption 空指针异常类:NullPointer ...

  9. OPC UA的监控项、订阅、和通知

    MonitoredItem 每个监控项均指明了要监控的项目(item)和用来发送通知的订阅. item可以是一个节点的属性(node attribute). MonitorItem可以监控一个属性,一 ...

  10. SQL 2005示例库(转载)

    sql2005数据库实例 从网上找还得麻烦,转了过来,点击就可以下载! 在学习SQL2005中离开不了SQL2005示例数据库,AdventureWorks数据库下载安装,,northwind数据库下 ...