TaskTracker节点向JobTracker汇报当前节点的运行时信息时候,是将运行状态信息同心跳报告一起发送给JobTracker的,主要包括TaskTracker的基本信息、节点资源使用信息、各任务状态等。所以信息被序列化为TaskTrackerStatus实例对象。每次发送心跳报告的时候,会重新构造一个Status对象,并重置这些信息,而且需要主要的是每次发送的status对象的大小是不一定的,因为很多信息的发送是有时间间隔的。这些操作主要位于方法transmitHeartBeat的上半部分代码:

 HeartbeatResponse transmitHeartBeat(long now) throws IOException {
// 计算是否发送任务计数器信息,间隔时间为${COUNTER_UPDATE_INTERVAL}对应的值为60s,不支持配置
boolean sendCounters;
if (now > (previousUpdate + COUNTER_UPDATE_INTERVAL)) {
sendCounters = true;
previousUpdate = now;
}
else {
sendCounters = false;
} //
// Check if the last heartbeat got through...
// if so then build the heartbeat information for the JobTracker;
// else resend the previous status information.
//
if (status == null) {
synchronized (this) {
status = new TaskTrackerStatus(taskTrackerName, localHostname,
httpPort,
cloneAndResetRunningTaskStatuses(
sendCounters),
failures,
maxMapSlots,
maxReduceSlots);
}
} else {
LOG.info("Resending 'status' to '" + jobTrackAddr.getHostName() +
"' with reponseId '" + heartbeatResponseId);
} //
// Check if we should ask for a new Task
// 计算节点资源使用信息
boolean askForNewTask;
long localMinSpaceStart;
synchronized (this) {
askForNewTask =
((status.countOccupiedMapSlots() < maxMapSlots ||
status.countOccupiedReduceSlots() < maxReduceSlots) &&
acceptNewTasks);
localMinSpaceStart = minSpaceStart;
}
if (askForNewTask) {
askForNewTask = enoughFreeSpace(localMinSpaceStart);
long freeDiskSpace = getFreeSpace();
long totVmem = getTotalVirtualMemoryOnTT();
long totPmem = getTotalPhysicalMemoryOnTT();
long availableVmem = getAvailableVirtualMemoryOnTT();
long availablePmem = getAvailablePhysicalMemoryOnTT();
long cumuCpuTime = getCumulativeCpuTimeOnTT();
long cpuFreq = getCpuFrequencyOnTT();
int numCpu = getNumProcessorsOnTT();
float cpuUsage = getCpuUsageOnTT(); status.getResourceStatus().setAvailableSpace(freeDiskSpace);
status.getResourceStatus().setTotalVirtualMemory(totVmem);
status.getResourceStatus().setTotalPhysicalMemory(totPmem);
status.getResourceStatus().setMapSlotMemorySizeOnTT(
mapSlotMemorySizeOnTT);
status.getResourceStatus().setReduceSlotMemorySizeOnTT(
reduceSlotSizeMemoryOnTT);
status.getResourceStatus().setAvailableVirtualMemory(availableVmem);
status.getResourceStatus().setAvailablePhysicalMemory(availablePmem);
status.getResourceStatus().setCumulativeCpuTime(cumuCpuTime);
status.getResourceStatus().setCpuFrequency(cpuFreq);
status.getResourceStatus().setNumProcessors(numCpu);
status.getResourceStatus().setCpuUsage(cpuUsage);
}
//add node health information 添加节点健康状态
TaskTrackerHealthStatus healthStatus = status.getHealthStatus();
synchronized (this) {
if (healthChecker != null) {
healthChecker.setHealthStatus(healthStatus);
} else {
healthStatus.setNodeHealthy(true);
healthStatus.setLastReported(0L);
healthStatus.setHealthReport("");
}
} ......
...//发送心跳报告
.....
synchronized (this) {
for (TaskStatus taskStatus : status.getTaskReports()) {
if (taskStatus.getRunState() != TaskStatus.State.RUNNING &&
taskStatus.getRunState() != TaskStatus.State.UNASSIGNED &&
taskStatus.getRunState() != TaskStatus.State.COMMIT_PENDING &&
!taskStatus.inTaskCleanupPhase()) {
if (taskStatus.getIsMap()) {
mapTotal--;
} else {
reduceTotal--;
}
myInstrumentation.completeTask(taskStatus.getTaskID());
runningTasks.remove(taskStatus.getTaskID());
}
} .....
// 其他代码
}

transmitHeartBeat

  1、创建TaskTrackerStatus实例对象status,创建代码如下:

status = new TaskTrackerStatus(taskTrackerName, localHostname, httpPort, cloneAndResetRunningTaskStatuses(sendCounters), failures, maxMapSlots,maxReduceSlots); 

  创建status对象的时候参数分别是: taskTrackerName-->当前节点名称,value为{"tracker_" + localHostname + ":" + taskReportAddress},其中taskReportAddress是为task服务的监听地址。

        localHostname-->当前节点的指定的host名称,配置参数变量为slave.host.name,如果不指定该参数,那么从mapred.tasktracker.dns.interface和mapred.tasktracker.dns.nameserver指定的dns中获取,默认为本地hostname。

        httpPort-->Http监听的端口号

        cloneAndResetRunningTaskStatuses(sendCounters)-->根据是否进行任务计数器信息发送标志,clone真正运行的task状态信息

        failures-->当前节点上失败的任务次数,用于判断当前节点的完整性,当该值达到最大标准的时候,JobTracker不会再给该节点分配任务信息。

        maxMapSlots, maxReduceSlots-->该节点运行的最大slot个数。

  2、判断是否允许分配任务给该节点,这个是先通过判断当前节点的空闲slot个数,然后通过判断当前节点的磁盘剩余量来达到的。代码如下:

askForNewTask = ((status.countOccupiedMapSlots() < maxMapSlots || status.countOccupiedReduceSlots() < maxReduceSlots) && acceptNewTasks);
askForNewTask = enoughFreeSpace(localMinSpaceStart); // 其中localMinSpaceStart为配置中给定的${mapred.local.dir.minspacestart},默认为0

  当满足第一个条件:使用的slot个数小于总slot个数的时候,那么给JobTracker发送节点资源使用情况。当满足第二个条件的时候,允许JobTracker给当前节点分配任务。

  3、初始化资源使用情况,主要是设置一系列的磁盘、内存等资源信息等,代码如下:

      long freeDiskSpace = getFreeSpace(); // 获取剩余的磁盘大小
long totVmem = getTotalVirtualMemoryOnTT(); // 获取总的虚拟内存
long totPmem = getTotalPhysicalMemoryOnTT(); // 获取总的物理内存
long availableVmem = getAvailableVirtualMemoryOnTT(); // 获取可用的虚拟内存
long availablePmem = getAvailablePhysicalMemoryOnTT(); // 获取可用的物理内存
long cumuCpuTime = getCumulativeCpuTimeOnTT(); // 获取累积cpu时间
long cpuFreq = getCpuFrequencyOnTT(); // 获取cpu频率
int numCpu = getNumProcessorsOnTT(); // 获取总的进程数
float cpuUsage = getCpuUsageOnTT(); // 获取cpu可用比例 status.getResourceStatus().setAvailableSpace(freeDiskSpace);
status.getResourceStatus().setTotalVirtualMemory(totVmem);
status.getResourceStatus().setTotalPhysicalMemory(totPmem);
status.getResourceStatus().setMapSlotMemorySizeOnTT(mapSlotMemorySizeOnTT); // 设置map阶段slot允许的内存大小, ${mapred.cluster.map.memory.mb}
status.getResourceStatus().setReduceSlotMemorySizeOnTT(reduceSlotSizeMemoryOnTT); // 设置reduce阶段slot允许的内存大小, ${mapred.cluster.reduce.memory.mb}
status.getResourceStatus().setAvailableVirtualMemory(availableVmem);
status.getResourceStatus().setAvailablePhysicalMemory(availablePmem);
status.getResourceStatus().setCumulativeCpuTime(cumuCpuTime);
status.getResourceStatus().setCpuFrequency(cpuFreq);
status.getResourceStatus().setNumProcessors(numCpu);
status.getResourceStatus().setCpuUsage(cpuUsage);

  4、获取当前节点的监控状态,获取当前节点的监控状态是有线程NodeHealthCheckerService来周期性的检查的,可以通过配置一个监控脚本来实现,默认为不实现。详细分析见TaskTracker源码分析(TaskTracker节点健康状况监控)

  5、发送心跳报告

  6、处理当前真正运行的Task,处理规则是:只要task不是出于运行、就绪、提交挂起或者cleanup阶段,那么就将该task设置为完成状态,从真正运行的task列表中移除,并针对该task是map阶段或者reduce阶段,分别对map/reduce solt进行操作。

  7、完成发送。

  发送的状态对象是org.apache.hadoop.mapred.TaskTrackerStatus,主要属性有:

  String trackerName; // task tracker 节点名称
String host; // 主机名
int httpPort; // http web监听端口
int failures; // 在该节点上失败的task次数
List<TaskStatus> taskReports; // 当前节点上真正运行的各个人物的状态 volatile long lastSeen; // 上次汇报时间
private int maxMapTasks; // 当前节点上允许的最大map slot个数
private int maxReduceTasks; // 当前节点上允许的最大reduce slot个数
private TaskTrackerHealthStatus healthStatus; // 当前节点的健康状态对象 public static final int UNAVAILABLE = -1; // 是否不可用
private ResourceStatus resStatus; // 当前节点的资源对象

  其中ResourceStatus和TaskTrackerHealthStatus分别表示当前节点的资源信息和状态信息,是一个简单的model类。在这里不做分析。

  TaskStatus类全称为org.apache.hadoop.mapred.TaskStatus。主要保存当前TaskTracker上运行的所有任务的运行状态,基本属性如下:

  private final TaskAttemptID taskid; // task任务id
private float progress; // 任务执行进度,0-1.0
private volatile State runState; // 任务运行所处状态,详见TaskStatus.State枚举类
private String diagnosticInfo; // 诊断信息,一般为异常信息或者错误信息
private String stateString; // 字符串信息的运行状态
private String taskTracker; // 所属task tracker名称
private int numSlots; // 运行该task所需的slot个数,默认为1 private long startTime; // 任务启动时间
private long finishTime; // 任务完成时间
private long outputSize = -1L; // 输出数据量 private volatile Phase phase = Phase.STARTING; // 任务运行阶段,详见TaskStatus.Phase枚举类
private Counters counters; // 该任务中定义的计数器(包括系统自带计数器和用户自定义计数器)
private boolean includeCounters; // 是否包含计数器,计数器没个60s发送一次,也就是说每隔60s,发送的数据中包含一次计数器
private SortedRanges.Range nextRecordRange = new SortedRanges.Range(); // 下一个要处理的数据区间,用于定位坏记录所在的空间

  ===================================

  ResourceStatus实例对象resStatus的属性是由抽象类ResourceCalculatorPlugin来获取的,如果不指定该抽象类的具体实现类,那么获取的value值全部都是-1。在linux平台上,默认实现为LinuxResourceCalculatorPlugin类。

    // 创建获取资源的对象
Class<? extends ResourceCalculatorPlugin> clazz = fConf.getClass(TT_RESOURCE_CALCULATOR_PLUGIN,
null, ResourceCalculatorPlugin.class);
resourceCalculatorPlugin = ResourceCalculatorPlugin.getResourceCalculatorPlugin(clazz, fConf);

  另外,用户可以自定义该实现类,配置参数为${mapreduce.tasktracker.resourcecalculatorplugin},默认为空。获取代码如下:

public static ResourceCalculatorPlugin getResourceCalculatorPlugin(
Class<? extends ResourceCalculatorPlugin> clazz, Configuration conf) { if (clazz != null) {
return ReflectionUtils.newInstance(clazz, conf); // 如果已经配置了class,那么直接使用配置的class
} // No class given, try a os specific class
try {
String osName = System.getProperty("os.name"); // 获取操作系统
if (osName.startsWith("Linux")) { // 如果是linux
return new LinuxResourceCalculatorPlugin(); // 使用已经实现的一种
}
} catch (SecurityException se) {
// Failed to get Operating System name.
return null;
} // Not supported on this system.
return null;
}

  在LinuxResourceCalculatorPlugin中,其实获取系统的资源信息都是通过读取proc虚拟文件系统中的一些信息来达成的,比如从/proc/meminfo中读取内存,从/proc/cpuinfo中读取cpu信息等。

[Hadoop] - TaskTracker源码分析(状态发送)的更多相关文章

  1. [Hadoop] - TaskTracker源码分析

    在Hadoop1.x版本中,MapReduce采用master/salve架构,TaskTracker就是这个架构中的slave部分.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. 【Netty源码分析】发送数据过程

    前面两篇博客[Netty源码分析]Netty服务端bind端口过程和[Netty源码分析]客户端connect服务端过程中我们分别介绍了服务端绑定端口和客户端连接到服务端的过程,接下来我们分析一下数据 ...

  5. RocketMQ 源码分析 —— Message 发送与接收

    1.概述 Producer 发送消息.主要是同步发送消息源码,涉及到 异步/Oneway发送消息,事务消息会跳过. Broker 接收消息.(存储消息在<RocketMQ 源码分析 —— Mes ...

  6. Hadoop TextInputFormat源码分析

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

  7. Hadoop TaskScheduler源码分析

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

  8. MPTCP 源码分析(四) 发送和接收数据

    简述:      MPTCP在发送数据方面和TCP的区别是可以从多条路径中选择一条 路径来发送数据.MPTCP在接收数据方面与TCP的区别是子路径对无序包 进行重排后,MPTCP的mpcb需要多所有子 ...

  9. Hadoop2源码分析-准备篇

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

随机推荐

  1. 浅谈IOS8之size class

    文章目录 1. 简介 2. 实验 3. 实战 3.1. 修改 Constraints 3.2. 安装和卸载 Constraints 3.3. 安装和卸载 View 3.4. 其他 4. 后话 以前和安 ...

  2. 处理JSON格式的数据

    JSON格式的数据是最常用的数据格式,处理方法的选择就显得比较重要了.我常用的一种是用对象来接收,然后保存在数组中,需要时直接从数组中取值.下面列出一个小例子. .h文件中: #import < ...

  3. Dom编程(二)

    document是window对象的一个属性,因为使用window对象成员的时候可以省略window.,所以一般直接写document  document的方法: (1)write:向文档中写入内容. ...

  4. PHP7新特性

    重写ZenVM,性能比PHP5.6提升300% 新特性: 1.变量类型(为PHP7.1的JIT特性做准备)function test(int $a, string $b, array $c) : in ...

  5. IOS开发-OC学习-MD5加密

    MD5的全称是Message-Digest Algorithm 5. MD5加密算法为现在应用最广泛的哈希算法之一,该算法广泛应用于互联网网站的用户文件加密,能够将用户密码加密为128位的长整数.数据 ...

  6. EF 实体字段设置主键和自增

    [Key] //主键 [DatabaseGenerated(DatabaseGeneratedOption.Identity)] //设置自增 public int id { get; set; } ...

  7. java名词解释,让你更好理解

    Java 开发工具包 (JDK) Java开发工具包是Java环境的核心组件,并提供编译.调试和运行一个Java程序所需的所有工具,可执行文件和二进制文件.JDK是一个平台特定的软件,有针对Windo ...

  8. java中String相等问题

    java中判断两个字符串是否相等的问题   判断两个字符串是否相等的问题.在编程中,通常比较两个字符串是否相同的表达式是"==",但在java中不能这么写.在java中,用的是eq ...

  9. 【单调栈】hdu1506 Largest Rectangle in a Histogram

    单调栈的介绍及一些基本性质 http://blog.csdn.net/liujian20150808/article/details/50752861 依次把矩形塞进单调栈,保持其单增,矩形中的元素是 ...

  10. centos 修改/etc/fstab后无法启动

    今天做实验,增加了一个磁盘sdb1,而且也增加了自动挂载的功能/etc/fstab里增加了记录. 重新启动服务器的时候,系统启动不了了. 系统提示: 按提示 输入 root的密码,进入以Repair ...