在Hadoop1.x版本中,MapReduce采用master/salve架构,TaskTracker就是这个架构中的slave部分。TaskTracker以服务组件的形式存在,负责任务的执行和任务状态的汇报。TaskTracker是hadoop集群中运行在各个节点上的服务。扮演着“通信交通”的角色,是JobTracker和Task之间的“沟通桥梁”,一方面,TaskTracker发送心跳信息到JobTracker,并接收和执行返回的各种任务命令,比如运行任务(launchTaskAction),提交任务(SubmitTaskAction),杀死任务(KillTaskAction),杀死job(KillJobAction),重新初始化(TaskTrackerReinitAction)。另一方面,接收Task的汇报信息并发送需要执行的任务命令。简单来说,就是两个功能:汇报心跳和执行命令。


一、TaskTracker启动过程分析

  TaskTracker服务由类org.apache.hadoop.mapred.TaskTracker来实现。该类实现四个接口,分别是MRContents(常量接口),TaskUmbilicalProtocol(和Task通信协议接口),Runnable(线程接口,目的是以线程的方式启动TaskTracker),TaskTrackerMXBean(JMX MXBean,为了其他第三方监控软件监控)。

/**
* TaskTracker是一个独立的服务,所以有一个main方法。
*/
public static void main(String argv[]) throws Exception {
...... 打印信息,以及检查argv参数
try {
JobConf conf=new JobConf();
...... JMX信息设置
TaskTracker tt = new TaskTracker(conf); // 创建TaskTracker对象
MBeans.register("TaskTracker", "TaskTrackerInfo", tt); // 注册MXBean
tt.run(); // 执行
} catch (Throwable e) {
..... 异常处理
}
}

  TaskTracker在构造函数中初始化一些重要的对象和线程,在run方法中维护一个和JobTracker通信的RPC连接。接下来分别分析构造函数和run方法。

  1、重要变量和对象

    TaskTracker中的成员变量主要作用是用于管理节点和监控节点上的任务。这里简单介绍一些比较有用的变量以及它们的默认值和意义。

变量名 变量修饰符 默认值 意义解释
running volatile boolean  true  TaskTracker是否处于运行状态,true表示处于运行状态 
lastCheckDirsTime private long 0 最近检查时间
lastNumFailures private int 0 最近检查失败个数
jobTrackAddr InetSocketAddress   JobTracker的网络地址
taskReportAddress InetSocketAddress   TaskTracker和Task通信的网络地址
taskReportServer Server   RPC server,用于TaskTracker和Task间通信
jobClient InterTrackerProtocol   RPC client,用于和JobTracker通信
heartbeatResponseId short -1 心跳响应id
status TaskTrackerStatus null TaskTrackerStatus状态
server HttpServer   将TaskTracker信息显示到web界面
shuttingDown volatile boolean false 关闭
tasks Map<TaskAttemptID,TaskInProgress> hashmap 该节点上TID和TIP的映射关系
runningTasks Map<TaskAttemptID,TaskInProgress> null 该节点上正在运行的TID和TIP的映射关系
runningJobs Map<JobID,RunningJob> treemap 该节点上正在运行的作用列表,如果某个作业中的任务在该节点上运行,那么将该任务添加进入
acceptNewTasks boolean true 是否接受新任务,每次给JobTracker汇报心跳的时候带上该值。
maxMapSlots private int 0 该节点上配置的Map slot数目
maxReduceSlots private int 0 该节点上配置的Reduce slot数目
failures private int 0 该节点上失败的job次数
heartbeatInterval private volatile int 3000(ms) 心跳间隔时间,默认3s
aclsManager ACLsManager   作业访问权限控制对象
taskController TaskController   用于控制任务的初始化,终结和清洗工作
userLogManager UserLogManager   用户日志管理
jvmManager JvmManager   JVM管理
distributedCacheManager TrackerDistributedCacheManager   分布式缓存管理
mapEventsFetcher MapEventsFetcherThread   获取以及完成的MapTask列表,为Reduce Task远程copy提供前期准备
taskMemoryManager TaskMemoryManagerThread   任务内存监控
taskLauncher TaskLauncher   启动任务
localizer Localizer   任务本地化
healthChecker NodeHealthCheckerService   节点健康状况检查
jettyBugMonitor JettyBugMonitor   应对jetty中的bug启动的一个线程

    这些变量和对象的初始化工作基本上均放在构造函数中完成,现在看看构造函数:

........
FILE_CACHE_SIZE = conf.getInt("mapred.tasktracker.file.cache.size", 2000); // 获取文件cache大小,默认2000
maxMapSlots = conf.getInt("mapred.tasktracker.map.tasks.maximum", 2); // 获取配置的map slot大小,默认2
maxReduceSlots = conf.getInt("mapred.tasktracker.reduce.tasks.maximum", 2); // 获取配置的reduce slot个数,默认为2
diskHealthCheckInterval = conf.getLong(DISK_HEALTH_CHECK_INTERVAL_PROPERTY, DEFAULT_DISK_HEALTH_CHECK_INTERVAL); // 获取节点健康检查间隔时间,默认为60s
..........
taskController = (TaskController) ReflectionUtils.newInstance(taskControllerClass, fConf); // 创建控制器对象
..........
initialize(); // 初始化
.........
server.start(); // 启动httpserver
this.httpPort = server.getPort();
checkJettyPort(httpPort); // 检查jetty服务器,由于当端口号为小于0的情况下,jetty有bug,所以在这种情况下,设置shuttingDown为true。

    在构造函数中,除了获取一些基本的设置参数外,只初始化了taskController,server等。其他的初始化工作是调用方法initialize完成的。

// RPC initialization
int max = maxMapSlots > maxReduceSlots ? maxMapSlots : maxReduceSlots; // RPC初始值,采用最大的slot值。
//set the num handlers to max*2 since canCommit may wait for the duration of a heartbeat RPC
// 创建和Task通信的Server端对象,线程大小为2倍的slot大小。
this.taskReportServer = RPC.getServer(this, bindAddress, tmpPort, 2 * max, false, this.fConf, this.jobTokenSecretManager);
this.taskReportServer.start(); // 启动
........
// Initialize DistributedCache
this.distributedCacheManager = new TrackerDistributedCacheManager(this.fConf, taskController); // 初始化分布式缓存系统
this.distributedCacheManager.startCleanupThread(); // 启动 this.jobClient = (InterTrackerProtocol)UserGroupInformation.getLoginUser().doAs(
    new PrivilegedExceptionAction<Object>() {
        public Object run() throws IOException {
            return RPC.waitForProxy(InterTrackerProtocol.class,InterTrackerProtocol.versionID,jobTrackAddr, fConf);
        }
    }); // 创建和JobTracker通信的客户端对象
......
// 创建获取map的线程
this.mapEventsFetcher = new MapEventsFetcherThread();
mapEventsFetcher.setDaemon(true);
mapEventsFetcher.setName("Map-events fetcher for all reduce tasks " + "on " + taskTrackerName);
mapEventsFetcher.start();
.............
// 创建map/reduce任务启动线程并run
mapLauncher = new TaskLauncher(TaskType.MAP, maxMapSlots);
reduceLauncher = new TaskLauncher(TaskType.REDUCE, maxReduceSlots);
mapLauncher.start();
reduceLauncher.start();

    我们可以看到基本上所有涉及到的变量或者对象都已经完成了初始化并启动,至此TaskTracker的初始化工作基本完成。

二、和JobTracker的交互

  1、单次心跳发送

    Hadoop中的所有心跳机制均采用pull通信模型,即master从不会主动与slave通信,而总是被动的等待slave汇报信息并领取其对应的命令。TaskTracker周期性的向JobTracker汇报信息就是这种模式。

    在TaskTracker中的run方法中,维护一个无线循环,用于通过心跳发送状态信息和接收命令,代码如下:

boolean denied = false; // 是否JobTracker拒绝TaskTracker的心跳报告
while (running && !shuttingDown && !denied) { // 如果当然TaskTracker处于运行状态,而且jetty服务器运行正常,并且没有被JobTracker拒绝请求,那么就一直循环
boolean staleState = false; // 状态信息
try {
// This while-loop attempts reconnects if we get network errors
while (running && !staleState && !shuttingDown && !denied) { // 外面的条件加上如果状态信息为false,那么就一直循环,这种方式是为了保证,当网络出现问题的时候,能够重新连接。
try {
State osState = offerService(); // 进行具体和JobTracker的通信
if (osState == State.STALE) { // 返回的状态不正常
staleState = true;
} else if (osState == State.DENIED) { // 返回的状态不正常
denied = true;
}
} catch (Exception ex) {
// 异常处理
}
}
} finally {
close(); // 只要是出现异常,或者是退出死循环,那么都关闭资源,重新启动资源
}
if (shuttingDown) { return; } // 如果是jetty服务器问题,那么直接退出
initialize(); // 网络出现问题,重新连接
}
if (denied) { // 如果JobTracker拒绝请求,那么关闭httpserver
shutdown();
}

  其中offerService中的函数代码框架是:

while (running && !shuttingDown) {// Send the heartbeat and process the jobtracker's directives
// 发送心跳报告,并获取任务命令
HeartbeatResponse heartbeatResponse = transmitHeartBeat(now); if (actions != null){ // 如果命令不为空,那就处理命令
for(TaskTrackerAction action: actions) {
if (action instanceof LaunchTaskAction) { // 如果命令为启动task命令
addToTaskQueue((LaunchTaskAction)action);
} else if (action instanceof CommitTaskAction) { // 提交task命令
...
} else {
....
}
}
}
markUnresponsiveTasks(); // 杀死一定时间内无反应的任务
killOverflowingTasks(); // 当磁盘空间少于mapred.local.dir.minspacekill时候,寻找合适的任务将其杀死以释放空间。

  TaskTracker的单次心跳发送过程为:

    步骤1: 判断是否到达心跳发送时间

      心跳发送时间由集群的规模和任务的运行情况来决定。JobTracker能够根据当前集群的规模和状态动态调整心跳间隔,并将下一次的心跳间隔时间放到应答中返回给TaskTracker。任务运行情况,当TaskTracker发送有任务或者job执行失败,就会立即缩短间隔时间,以便将任务完成或者任务失败的信息发送给JobTracker,进而可以快速的分配新的任务,主要作用是为了提高任务的响应时间和资源的利用率。需要配置参数:

      mapreduce.tasktracker.outofband.beartbeat: 决定是否启用,默认为flase,不启用。

      mapreduce.tasktracker.outofband.hearbeat.damper: 心跳收缩因子。默认值为10000。

      计算时间间隔算法为:(heartbeatInterval / (numFinishedTasks * oobHeartbeatDamper + 1)),其中heartbeatInterval为从JobTracker端获取的心跳间隔时间(默认为3000),numberFinishedTasks为完成的任务个数,oobHeartbeatDammper为收缩因子的值。

    步骤2: 如果TaskTracker刚启动,检查TaskTracker和JobTracker的版本信息是否一致

      只有与JobTracker的版本信息一致,才可以发送心跳报告。版本信息由hadoop版本号,修订版本号,代码编译用户和校验和四部分组成。比如:"1.0.0 from 12555 by kashad source checksum 423dcd5a752eddd8e45ead6fd5ff9a24",hadoop版本号2.5.0,修订版本号为12555,编译者为kashad,校验和为423dcd5a752eddd8e45ead6fd5ff9a24。

    步骤3: 检测磁盘是否损坏

      由于存储中间结果的输入目录(mapred.local.dir)是存储在本地的,而且没有备份文档,所以当磁盘出现损坏的时候,需要TaskTracker重新初始化。TaskTracker周期性(间隔由mapred.disk.healthChecker.interval决定,默认为60s)的检查磁盘是否损坏。

    步骤4: 发送心跳

      TaskTracker将当前节点的运行信息发送给JobTracker,同时接收JobTracker的各种命令。

    步骤5: 接收并执行各种命令

      主要分为三种:job重新运行命令,TaskTracker重新初始化命令,其他命令。

待续................

[Hadoop] - TaskTracker源码分析的更多相关文章

  1. [Hadoop] - TaskTracker源码分析(状态发送)

    TaskTracker节点向JobTracker汇报当前节点的运行时信息时候,是将运行状态信息同心跳报告一起发送给JobTracker的,主要包括TaskTracker的基本信息.节点资源使用信息.各 ...

  2. [Hadoop] - TaskTracker源码分析(TaskTracker节点健康状况监控)

    在TaskTracker中对象healthStatus保存了当前节点的健康状况,对应的类是org.apache.hadoop.mapred.TaskTrackerStatus.TaskTrackerH ...

  3. Hadoop RPC源码分析

    Hadoop RPC源码分析 上一篇文章http://www.cnblogs.com/dycg/p/rpc.html 讲了Hadoop RPC的使用方法,这一次我们从demo中一层层进行分析. RPC ...

  4. Hadoop TextInputFormat源码分析

    from:http://blog.csdn.net/lzm1340458776/article/details/42707047 InputFormat主要用于描述输入数据的格式(我们只分析新API, ...

  5. Hadoop TaskScheduler源码分析

    TaskScheduler是MapReduce中的任务调度器.在MapReduce中,JobTracker接收JobClient提交的Job,将它们按InputFormat的划分以及其他相关配置,生成 ...

  6. Hadoop2源码分析-准备篇

    1.概述 我们已经能够搭建一个高可用的Hadoop平台了,也熟悉并掌握了一个项目在Hadoop平台下的开发流程,基于Hadoop的一些套件我们也能够使用,并且能利用这些套件进行一些任务的开发.在Had ...

  7. hadoop的RPC机制 -源码分析

    这些天一直奔波于长沙和武汉之间,忙着腾讯的笔试.面试,以至于对hadoop RPC(Remote Procedure Call Protocol ,远程过程调用协议,它是一种通过网络从远程计算机程序上 ...

  8. Hadoop心跳机制源码分析

    正文: 一.体系背景 首先和大家说明一下:hadoop的心跳机制的底层是通过RPC机制实现的,这篇文章我只介绍心跳实现的代码,对于底层的具体实现,大家可以参考我的另几篇博客: 1. hadoop的RP ...

  9. Hadoop的RPC机制源码分析

    分析对象: hadoop版本:hadoop 0.20.203.0 必备技术点: 1. 动态代理(参考 :http://www.cnblogs.com/sh425/p/6893662.html )2. ...

随机推荐

  1. Java对象嵌套

    1.基础篇 Java面向对象东西太深奥了,本文只是发表一点自己的见解. 首先 举个栗子!! 汽车, 我们先给汽车定义个轮胎类  有一个属性名 轮胎尺寸 /** *定义一个轮胎类 */ class Wh ...

  2. ucos队列的实现--源码分析

    之前说到事件,讲了事件,信号量和互斥信号量,还有一个队列没说,今天说说队列. 队列是用在任务之间传送多个消息的时候,a任务发送消息,b任务发送消息,然后c任务可以依次去提取出b和a传递的消息,不会造成 ...

  3. 360路由器设置网段ip

    路由器设置->高级设置->修改路由器地址

  4. Test 17

    BZ OI 队测 T1: 题目大意: 喵星系有n个星球,标号为1到n,星球以及星球间的航线形成一棵树. 所有星球间的双向航线的长度都为1.小昕要在若干个星球建矿石仓库,设立每个仓库的费用为K.对于未设 ...

  5. 在MVC中添加拦截器实现登录后的权限验证

    1.新建一个类 (以下实现了打印日志功能) using System; using System.Collections.Generic; using System.Linq; using Syste ...

  6. ipyparallel WordCount实现

            ipyparallel 之中,可以利用多个engine同时运行一个任务来加快处理的速度.在ipyparallel之中,集群被抽象为view,包括direct_view和balanced ...

  7. 1.1.1.持久化存储协调器(Core Data 应用程序实践指南)

    持久化存储协调器(persistent store coordinator)里面包含一份持久化存储区,而存储区里又含有数据表里的若干行数据. 与原子存储不同,SQLite数据库会在用户提交变更日志时进 ...

  8. easyui datagrid 列排序

    1.js设置 //=====================数据加载===================== /** * grid加载数据 * * @returns */ function grid ...

  9. 第一个Servlet程序及分析

    第一个Servlet程序: package cc.openhome; import java.io.IOException; import java.io.PrintWriter; import ja ...

  10. hadoop学习笔记--集群搭建

    注:大家常说的ssh其实就是一个免密码访问的东西,为了简化操作的,不用每次访问其他节点重新输入密码.但是要想配置如下: .在每台机器上执行 ssh-keygen -t rsa,连敲三次回车键(即设置空 ...