[Hadoop] - TaskTracker源码分析(状态发送)
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源码分析(状态发送)的更多相关文章
- [Hadoop] - TaskTracker源码分析
在Hadoop1.x版本中,MapReduce采用master/salve架构,TaskTracker就是这个架构中的slave部分.TaskTracker以服务组件的形式存在,负责任务的执行和任务状 ...
- [Hadoop] - TaskTracker源码分析(TaskTracker节点健康状况监控)
在TaskTracker中对象healthStatus保存了当前节点的健康状况,对应的类是org.apache.hadoop.mapred.TaskTrackerStatus.TaskTrackerH ...
- Hadoop RPC源码分析
Hadoop RPC源码分析 上一篇文章http://www.cnblogs.com/dycg/p/rpc.html 讲了Hadoop RPC的使用方法,这一次我们从demo中一层层进行分析. RPC ...
- 【Netty源码分析】发送数据过程
前面两篇博客[Netty源码分析]Netty服务端bind端口过程和[Netty源码分析]客户端connect服务端过程中我们分别介绍了服务端绑定端口和客户端连接到服务端的过程,接下来我们分析一下数据 ...
- RocketMQ 源码分析 —— Message 发送与接收
1.概述 Producer 发送消息.主要是同步发送消息源码,涉及到 异步/Oneway发送消息,事务消息会跳过. Broker 接收消息.(存储消息在<RocketMQ 源码分析 —— Mes ...
- Hadoop TextInputFormat源码分析
from:http://blog.csdn.net/lzm1340458776/article/details/42707047 InputFormat主要用于描述输入数据的格式(我们只分析新API, ...
- Hadoop TaskScheduler源码分析
TaskScheduler是MapReduce中的任务调度器.在MapReduce中,JobTracker接收JobClient提交的Job,将它们按InputFormat的划分以及其他相关配置,生成 ...
- MPTCP 源码分析(四) 发送和接收数据
简述: MPTCP在发送数据方面和TCP的区别是可以从多条路径中选择一条 路径来发送数据.MPTCP在接收数据方面与TCP的区别是子路径对无序包 进行重排后,MPTCP的mpcb需要多所有子 ...
- Hadoop2源码分析-准备篇
1.概述 我们已经能够搭建一个高可用的Hadoop平台了,也熟悉并掌握了一个项目在Hadoop平台下的开发流程,基于Hadoop的一些套件我们也能够使用,并且能利用这些套件进行一些任务的开发.在Had ...
随机推荐
- sql数据库中查询第几条到第几条的数据
通用方法: select top 500 * from (select top 1000 * from UserSearchDatas order by ID) a order by ID desc ...
- HMC5883L地磁传感器驱动
霍尼韦尔 HMC5883L 是一种表面贴装的高集成模块,并带有数字接口的弱磁传感器芯片,应用于低成本罗盘和磁场检测领域.HMC5883L 包括最先进的高分辨率 HMC118X 系列磁阻传感器,并附带霍 ...
- Android实现版本更新
Android 实现从后台下载apk文件,保存到本地sd卡,使用系统安装apk,完成版本更新功能 LoadAppUtil.java import java.io.File; import java.i ...
- linux下简单限制网卡速度
Linux下限制网卡的带宽,可用来模拟服务器带宽耗尽,从而测试服务器在此时的访问效果. 1.安装iproute yum -y install iproute 2.限制eth0网卡的带宽为50kbit: ...
- Shell 基础
1.结构 #!指定执行脚本的shell #!/bin/sh # 注释行 命令和控制结构 2.修改权限 chmod +x ... 3 ...
- SVN官方版本下载地址
TortoiseSVN 客户端 & Language packs 语言包 : https://tortoisesvn.net/downloads.html VisualSVN 插件官方地址: ...
- plsql developer日期时间格式设置
1 工具->首选项->日期/时间都使用windows格式: 2 在环境变量加入 nls_date_format=YYYY-MM-DD HH24:MI:SS nls_timestamp_fo ...
- 使用AngularJS的三个重要原因
入门教程:http://www.ituring.com.cn/minibook/303 : http://angularjs.cn/tag/AngularJS 原因一:Google开发的框架 要知道开 ...
- OpenCV框架介绍
OpenCV框架介绍 概述 OpenCV是一个开放源代码的计算机视觉应用平台,由英特尔公司下属研发中心俄罗斯团队发起该项目,开源BSD证书,OpenCV的目标是实现实时计算机视觉,,是一个跨平台的计算 ...
- SQLSERVER如何导入数据保持ID不变(ID为自增主键)
使用SQL SERVER最操蛋的就是导入数据,以前用企业管理器直接导数据,导一次骂N次娘,在骂了微软无数次娘之后总结了一个方法揍合着还算受用. 其核心要点就是要将数据结构导入到目标数据库服务器上,再来 ...