1. 检查”mapred.hosts”文件中和”mapred.hosts.exclude”是否配置了允许接入或者拒绝的主机地址
2. 如果是重启TaskTracker发的心跳,则在FaultyTrackersInfo中标识该TaskTracker所在的主机为健康。如果不是重启的,则检查在指定时间窗口中该主机发生的错误是否超过阈值,如果不超过则把属于该主机的gray状态设置为false。如果指定时间窗口中该主机的错误为0了,则去除记录该主机为非正常状态。为什么不按照TaskTracker记录健康状态,而是按照所在的主机记录呢,一个主机可能存在多个TaskTracker。
3. 如果不是第一次发起心跳,并且在JobTracker中没有前一次心跳的记录,那么检查JobTracker是否重启过,如果重启过则在RecoveryManager去除发送本次心跳的TaskTracker记录。如果JobTracker没有重启过,则返回重新初始化Action给发起本次心跳的TaskTracker。
4. 处理心跳(JobTracker.processHeartbeat())
1) 更新TaskTracker状态(JobTracker.updateTaskTrackerStatus())
a) 更新JobTracker中totalMaps,totalReduces,occupiedMapSlots,occupiedReduceSlots,totalMapTaskCapacity,totalReduceTaskCapacity的总值,更新的方式是先减去taskTrackers记录的老的TaskTracker状态的值,然后再加上heartbeat接收到最新的TaskTracker状态的值。
b) 更新taskTrackers记录的TaskTracker为该心跳收到的状态信息。
c) 如果心跳接收到的TaskTracker的状态信息为null,则减去uniqueHostsMap中记录的该TaskTracker所在主机对应的TaskTracker的个数值。
2) 如果心跳指明是第一次发起心跳,则从JobTracker中清除已记录该TaskTracker的任务相关信息(JobTracker.lostTaskTracker())
a) 去除trackerToTasksToCleanup,trackerToJobsToCleanup中记录的该TaskTracker的cleanup任务。
b) 在recoveryManager中去除需要对该TaskTracker进行恢复管理。
c) 对trackerToTaskMap记录的该TaskTracker中还在运行的Task发起failedTask处理,如果该task是还在运行中的非setup和cleanup任务则更新状态为killed_unclean否则更新状态为killed。更新为killed_unclean后会生成Task Clean Action通知TaskTracker对该任务进行中止处理。对已经结束的Task从taskidToTrackerMap,trackerToTaskMap,taskidToTIPMap中清除。最后清除trackerToTaskMap记录的任务信息。
d) unreserve该每个JobInProgress中记录的对每个TaskTracker保留的slot。这部分代码似乎没有启作用。因为TaskTracker.reserveSlots()该方法没有调用,没有reserve,那么unreserve也没作用了。
3) 如果不是第一次发起的心跳,但是没有找到上次发起心跳的信息,则清除TaskTracker信息,认为是不正常的TaskTracker。清除的信息有先减去原来totalMaps,totalReduces,occupiedMapSlots,occupiedReduceSlots,totalMapTaskCapacity,totalReduceTaskCapacity的总值,然后从taskTrackers中去除TaskTracker的信息,最后减去uniqueHostsMap中记录的该TraskTracker所在主机对应的TaskTracker的个数。并且心跳消息将不处理以下所有步骤,直接向TaskTracker返回重新初始化的Action。
4) 如果是第一次发起心跳,则在JobTracker中添加TaskTracker的信息。
a) 在trackerExpiryQueue中添加进行超时检查TaskTracker信息。超时检查看TaskTracker超时检查。
b) 如果该TaskTracker的主机还未加入到整个分布式计算环境拓扑中,则把该主机解析后放到拓扑中。
c) 在hostnameToTaskTracker队列中添加所属主机对应的TaskTracker信息。
5) 更新TaskTracker的Task状态(JobTracker.updateTaskStatuses())
a) 对该TaskTracker上的Task不再检查超时,因为心跳时传过来Task的信息,代表该Task已经在处理中,因此从expireLaunchingTasks去除超时检查。
b) 如果该Task所属的JobInProgress为空,则在trackerToJobsToCleanup中添加所有运行该Job任务的TaskTracker关于这个Job的标识。在心跳返回给TaskTracker时携带该TaskTracker所标识的该Job的Clean upaction。
c) 如果该Task所属的JobInProgress还未初始化完成,则在trackerToTasksToCleanup中添加该TaskTracker上这个Task 的Cleanup标识。在心跳返回给TaskTracker时携带该Task Cleanup action。
d) 更新Job中的Task状态(JobInProgress.updateTaskStatus())
i. 如果该Task已经完成或者已经是failed或killed状态,但task还是报success状态,则更新success为killed。
ii. 如果该task所属的job已经完成,或者是job_failed或job_killed状态,如果Task的状态是 failed_unclean/killed_unclean,则重新设置为failed/killed,后续的操作将不再生成cleanup Action的task给TaskTracker,直接走failed/killed状态的操作。
iii. 对重复上报的success/failed/killed状态不更新。对已经成功或者失败的状态不更新到成功或者失败以前的状态(RUNNING/UNASSIGNED)。如果原先状态已经是failed/killed,但后续还在报非failed/killed状态则可能存在TaskTracker上执行task有异常,则在tasksToKill中标识该任务已经失败,但并不更新状态,并在返回给TaskTracker的heartbeat中生成KillTaskAction,让TaskTracker重新执行一次中止任务的Action。如果JobTracker在safemode,并且task的状态为failed,则状态更新为killed。只有对状态更新的,才继续做以下操作。(TaskInProgress.updateStatus())
iv. 如果Task的状态是succeeded,则做completedTask操作。
v. 如果Task的状态是commit_pending,则在该Task对应的TaskInProgress中记录需要commit的taskId操作。在返回给TaskTracker的heartbeat消息中生成CommitTaskAction操作。
vi. 如果Task的状态是failed_unclean/killed_unclean,则做incompleteSubTask操作,并在mapCleanupTasks/ reduceCleanupTasks中注册该任务号,在返回给TaskTracker的heartbeat消息中生成LaunchTaskAction,让TaskTracker执行该Task的clean操作。
vii. 如果Task为failed/killed状态,则执行failedTask操作。
e) 更新Job的监听(JobTracker.updateJobInProgressListeners())
6) 更新TaskTracker所在主机的健康状态。如果主机不健康则设置为故障状态,否则设置为正常状态。(JobTracker.updateNodeHealthStatus())
5.如果在心跳消息中标识该TaskTracker可接收分配任务并且该TaskTracker的状态时是正常运行的,并且TaskTracker不在safemode,则对该TaskTracker进行分派任务。所有任务执行时检查该TaskTracker上执行的任务失败次数是否超过所允许的最大失败次数,如果超过则不分配到该TaskTracker上执行,选择分配到那些运行更稳定的TaskTracker上,但是整个MapReduce环境中出故障的TaskTracker太多,那么超过某个阈值也继续分配在该TaskTracker执行,以防TaskTracker出故障太多,导致任务没有被及时分配执行(JobTracker.getSetupAndCleanupTasks())
1) 分配JOB Setup,分配Job Setup的前提是Job还在Prepare状态,该Job没有被Killed或者Failed,并且还没分配过Job Setup任务。JobSetup分为Map和Reduce两类。当该TaskTracker上所运行的Map Task已达上限,那么按照Reduce Task的类型分配JobSetup,使之当Reduce Task执行。如果Reduce Task也已达TaskTracker的运行上限,则不再分配任务给该TaskTracker。完成Job Setup任务后Job从Prepare状态转到RUNNING状态。
2) 分配Task Cleanup,当处理状态为failed_unclean或者killed_unclean时,在mapCleanupTasks/reduceCleanupTasks中注册该任务号,对注册需要clean up的任务分配给TaskTracker执行clean upaction。分配Task Cleanup的前提是Job还在RUNNING状态,该Job没有被Killed或者Failed。
3) 分配JOB Cleanup,分配Job Cleanup的前提是该Job在Prepare或者RUNNING状态,该Job可以再置killed或者failed为true下(这样在Job被killed或者failed下还可以分配Job cleanup任务执行),Job Setup任务已经分配执行过,还没分配过Job Cleanup任务,并且Map和Reduce任务全都分配执行完成。 JobClean分为Map和Reduce两类。当该TaskTracker上所运行的Map Task已达上限,那么按照Reduce Task的类型分配JobCleanup,使之当Reduce Task执行。如果Reduce Task也已达TaskTracker的运行上限,则不再分配任务给该TaskTracker。完成Job Clean任务后Job从RUNNING状态视任务的执行结果而定转到SUCCEEDED、Failed、Killed状态,并且执行对已完成Job进行清扫操作。
6. 如果Job没有可分配的Job setup Task,Cleanup Task,Job Cleanup Task,则开始分配Map和Reduce任务(JobQueueTaskScheduler.assignTasks())
1) 为了把执行任务的负荷均匀的分担到MapReduce的集群环境中,先计算每个TaskTracker的负荷比例,分别计算Map和Reduce的负荷比例,计算的方式是所有还未执行的Map/Reduce任务个数除以整个集群环境下能提供的执行Map/Reduce任务的slot数,然后把所有还未执行的任务占整个集群环境的负荷比例用到单个TaskTracker的负荷比例上,以达到负荷均匀分摊,通过这个比例计算出某个TaskTracker上能够提供的负荷(slot数)再减去当前已经占用执行的任务个数,就是该TaskTracker上当前能提供的计算能力(slot数)。
2) 集群环境需要预留一些计算资源(slot数)用于失败任务重新分配执行,或者任务的冗余执行(一个任务分配到多个TaskTracker执行,任何一个执行成功就认为该任务成功)。当集群环境所有Job的Map/Reduce任务数乘以padding系数再加上当前正在运行的任务数超过当前能提供的计算能力(slot数),则需要预留计算资源。当进行预留计算资源时,每次给TaskTracker分配任务时只分配一个,否则对该TaskTracker当前空闲的计算能力(slot数)都分配任务执行。
3) 如果该任务预计的输出结果比TaskTracker本地的存储空间大,则不分配该任务执行;如果该任务已经在运行中则不分配该任务;如果该任务已经在该TaskTracker上执行失败则不分配该任务,但是执行该任务失败的主机数大于等于当前集群的主机数则继续分配,以防失败主机数太多将不再分配执行,达到尽力而为。如果成功获取任务则记录在nonLocalRunningMaps和runningMapCache中记录,并从原有的队列或者map中删除已分配运行的任务,nonLocalRunningMaps和runningMapCache是记录已分配的任务,分别代表该任务执行的文件没有所属主机信息和存在所属主机信息。存在主机信息,那么首先将该任务分配到所属主机运行的TaskTracker上执行任务。
a) 首先从failedMaps中记录的任务集中获取任务。
b) 如果failedMaps没有获取任务分配,则继续从nonRunningMapCache获取所处理的文件所在主机在该TaskTracker主机上的任务。这样TaskTracker在处理任务时,处理的文件在主机本地,不用进行网络传输开销,这样任务处理叫做Node Local。如果没有这样的任务,则获取文件存储在与该主机属于同一机架(同一NetworkLocation,详情见MapReduce拓扑)下的任务,这样的任务叫做Rack Local。
c) 如果没有获取到Node Local和Rack Local任务,则以广度优先扫描nonRunningMapCache记录的文件存储在其它机架(其它NetworkLocation)下的任务。这样以防文件存储所在的主机没有运行TaskTracker,导致这样的任务不能被分配执行。但这样也会存在一个文件存储在机架A的任务被分配到机架B的TaskTracker执行的可能。
d) 如果广度优先扫描没有获取到任务,则从nonLocalMaps中获取没有携带所处理文件所在主机信息的任务。
4) 如果以上几个步骤都没有获取到所需要的任务,则说明当前没有任务可分配。那么是视是否需要冗余执行任务,以并行处理同一个任务,其中任何一个成功即为该任务执行成功。并行执行任务的前提是该任务还未分配在处理的文件所在的主机上的TaskTracker执行,并行执行的任务不超过2个,该任务已执行超过一定的时间并且还在执行中。
a) 首先从runningMapCache中获取已经运行的Node Local和Rack Local任务。
b) 如果没有Node Local和Rack Local任务则广度优先扫描runningMapCache获取其它机架(其它NetworkLocation)下的任务。
c) 如果广度优先扫描没有获取到任务,则从nonLocalRunningMaps获取已经运行的没有带文件主机信息的任务。
7. 当执行的Task所属Job不在RUNNING或者Prepare状态;当该任务已经完成,并且不是Map、cleanup、setup任务;当该任务处于COMMIT_PENDING,但该任务已经完成;当tasksToKill中标识了该任务;当trackerToTasksToCleanup中标识了该任务,以上四种情况生成KillTaskAction 任务分配给TaskTracker执行任务中止处理。
8. 当trackerToJobsToCleanup中标识了某个任务,则生成KillJobAction任务分配给该任务所属的TaskTracker执行中止Job处理。
9. 当task的状态是COMMIT_PENDING时,并且该任务还未结束,则生成CommitTaskAction任务分配给该任务所属的TaskTracker处理。
10. 对trackerToMarkedTasksMap中记录的任务做清除处理。从taskidToTIPMap,trackerToTaskMap,taskidToTrackerMap中去除记录的关于该任务的信息。trackerToMarkedTasksMap是在任务失败时;并行执行的任务已经成功完成并且Job不在running状态(在并行执行任务的情况下,其中一个已经完成,这个任务将标识killed并且记录在trackerToMarkedTasksMap中);在处理第一次接收到心跳时,但该TaskTracker上已存在Task的记录;Cleanup任务执行完毕后;在Job完成时对已经完成的map,reduce和setup任务进行记录(未完成还在running的任务,将会上报任务状态给JobTracker或者任务超时时进行删除),最后执行清除处理。