任务的申请、派发与执行
TaskTracker.run() 连接JobTracker
TaskTracker 的启动过程会初始化一系列参数和服务(另有单独的一节介绍),然后尝试连接JobTracker 服务(即必须实现InterTrackerProtocol 接口),如果连接断开,则会循环尝试连接JobTracker ,并重新初始化所有成员和参数,此过程参见run() 方法。
TaskTracker.offerService() 主循环
如果连接JobTracker 服务成功,TaskTracker 就会调用offerService() 函数进入主执行循环中。这个循环会每隔10 秒与JobTracker 通讯一次,调用transmitHeartBeat() 获得HeartbeatResponse 信息。然后调用HeartbeatResponse 的getActions() 函数获得JobTracker 传过来的所有指令即一个TaskTrackerAction 数组。再遍历这个数组,如果是一个新任务指令即LaunchTaskAction 则调用startNewTask() 函数执行新任务,
如果是 CommitTaskAction
否则加入到tasksToCleanup 队列,交给一个taskCleanupThread 线程来处理,如执行KillJobAction 或者KillTaskAction 等。
TaskTracker.transmitHeartBeat() 获取JobTracker 指令
在transmitHeartBeat() 函数处理中,TaskTracker 会创建一个新的TaskTrackerStatus 对象记录目前任务的执行状况,然后通过IPC 接口调用JobTracker 的heartbeat() 方法发送过去,并接受新的指令,即返回值TaskTrackerAction 数组。在这个调用之前,TaskTracker 会先检查目前执行的Task 数目以及本地磁盘的空间使用情况等,如果可以接收新的Task 则设置heartbeat() 的askForNewTask 参数为true 。操作成功后再更新相关的统计信息等。
JobTracker 调度作业第二步:派发任务
JobTracker 接到TaskTracker 的heartbeat() 调用后,首先会检查上一个心跳响应是否完成,是没要求启动或重启任务,如果一切正常,则会处理心跳。JobTracker 会使用它的调度器taskScheduler 来组装任务到一个任务列表tasks 中。具体实现在taskScheduler 的assignTasks() 方法。得到tasks 的数据后,把这些任务封装在一些LanuchTaskAction 中,发回给TaskTracker ,让它去执行任务。此时JobTracker 的hearbeat() 结束派发任务。
下面简单分析下 hadoop 默认的作业调度器 JobQueueTaskScheduler 怎么实现以上所说的 assignTasks() 方法。首先它会检查 TaskTracker 端还可以做多少个 map 和 reduce 任务,将要派发的任务数是否超出这个数,是否超出集群的任务平均剩余可负载数。如果都没超出,则为此 TaskTracker 分配一个 MapTask 或 ReduceTask 。产生 Map 任务使用 JobInProgress 的 obtainNewMapTask() 方法,实质上最后调用了 JobInProgress 的 findNewMapTask() 访问 nonRunningMapCache 得到 Map 任务的 TaskInProgress ;而产生 Reduce 任务使用 JobInProgress.obtainNewReduceTask() 方法,实质上最后调用了 JobInProgress 的 findNewReduceTask() 访问 nonRuningReduceCache 得到 Reduce 任务的 TaskInProgress 。