MapReduce调度与执行原理之任务调度(续)
前言 :本文旨在理清在Hadoop中一个MapReduce作业(Job)在提交到框架后的整个生命周期过程,权作总结和日后参考,如有问题,请不吝赐教。本文不涉及Hadoop的架构设计,如有兴趣请参考相关书籍和文献。在梳 理过程中,我对一些感兴趣的源码也会逐行研究学习,以期强化基础。
作者
:Jaytalent
开始日期
:2013年9月9日参考资料:【1】《Hadoop技术内幕--深入解析MapReduce架构设计与实现原理》董西成【2】 Hadoop 1.0.0 源码
上一篇文章的话题,说说调度器的任务选择机制。
【1】:
任务调度与监控
Collection<JobInProgress> jobQueue = jobQueueJobInProgressListener.getJobQueue();
对于FIFO调度器而言,队列即为对应监听器中使用的作业队列。然后,声明一个列表,用于保存选择的任务:
// Assigned tasks
List<Task> assignedTasks = new ArrayList<Task>();
接下来,计算队列中正在运行的和等待运行的map和reduce任务的数量:
// Compute (running + pending) map and reduce task numbers across pool
int remainingReduceLoad = 0;
int remainingMapLoad = 0;
synchronized (jobQueue) {
for (JobInProgress job : jobQueue) {
if (job.getStatus().getRunState() == JobStatus.RUNNING) {
remainingMapLoad += (job.desiredMaps() - job.finishedMaps());
if (job.scheduleReduces()) {
remainingReduceLoad +=
(job.desiredReduces() - job.finishedReduces());
}
}
}
}
其中,job.scheduleReduces方法判断当前map任务的总体进度是否满足reduce任务开始调度的条件,map任务完成的比例是否超过变量mapred.reduce.slowstart.completed.maps的值,若超过则计算reduce任务的剩余任务数。接下来,计算map和reduce任务的负载因子:
// Compute the 'load factor' for maps and reduces
double mapLoadFactor = 0.0;
if (clusterMapCapacity > 0) {
mapLoadFactor = (double)remainingMapLoad / clusterMapCapacity;
}
double reduceLoadFactor = 0.0;
if (clusterReduceCapacity > 0) {
reduceLoadFactor = (double)remainingReduceLoad / clusterReduceCapacity;
}
map任务负载因子定义为当前剩余的(正在执行的和等待开始的)map任务的总数与集群总的map资源数(map slot数目)的商值。reduce任务负载因子同理。计算负载因子的目的是根据TaskTracker的负载情况和集群总的负载情况将所有任务均衡地调度到各个TaskTracker以便均衡地使用各个结点上的资源。根据这种思想,可以计算出某个TaskTracker当前可用的slot数目:
final int trackerCurrentMapCapacity =
Math.min((int)Math.ceil(mapLoadFactor * trackerMapCapacity),
trackerMapCapacity);
int availableMapSlots = trackerCurrentMapCapacity - trackerRunningMaps;
boolean exceededMapPadding = false;
if (availableMapSlots > 0) {
exceededMapPadding =
exceededPadding(true, clusterStatus, trackerMapCapacity);
}
由此可见,可用slot定义为:根据集群总体负载均衡还有多少slot应该可用的数目减去实际已经在用的slot数目。注意,exceededMapPadding表示是否有足够的slot预留给推测执行的任务。所谓推测执行,是Hadoop为了防止某些任务执行过慢,为一些较慢任务启动一个备份任务,让该任务做相同的事情,并最终选用最先成功运行完成的任务计算结果为最终结果。推测执行机制日后关注。下面就是任务选择过程:
int numLocalMaps = 0;
int numNonLocalMaps = 0;
scheduleMaps:
for (int i=0; i < availableMapSlots; ++i) {
synchronized (jobQueue) {
for (JobInProgress job : jobQueue) {
if (job.getStatus().getRunState() != JobStatus.RUNNING) {
continue;
}
Task t = null;
// Try to schedule a node-local or rack-local Map task
t =
job.obtainNewNodeOrRackLocalMapTask(taskTrackerStatus,
numTaskTrackers, taskTrackerManager.getNumberOfUniqueHosts());
if (t != null) {
assignedTasks.add(t);
++numLocalMaps;
// Don't assign map tasks to the hilt!
// Leave some free slots in the cluster for future task-failures,
// speculative tasks etc. beyond the highest priority job
if (exceededMapPadding) {
break scheduleMaps;
}
// Try all jobs again for the next Map task
break;
}
// Try to schedule a node-local or rack-local Map task
t =
job.obtainNewNonLocalMapTask(taskTrackerStatus, numTaskTrackers,
taskTrackerManager.getNumberOfUniqueHosts());
if (t != null) {
assignedTasks.add(t);
++numNonLocalMaps; // We assign at most 1 off-switch or speculative task
// This is to prevent TaskTrackers from stealing local-tasks
// from other TaskTrackers.
break scheduleMaps;
}
}
}
}
int assignedMaps = assignedTasks.size();
对于某个空闲的slot,从队列中选择一个正在执行的作业,并调用obtainNewNodeOrRackLocalMapTask方法获得一个具有数据本地性地任务。若找到了这样的任务,将其放入结果列表中,并检查刚才获得的exceedingMapPadding的值。若不满足,则跳出最外层循环,重新为每个slot分配任务,以期有新的空闲slot产生,从而满足推测执行的需求。当找到一个数据本地性任务后,马上跳出对队列的遍历,为下一个slot分配任务。
int target = findNewMapTask(tts, clusterSize, numUniqueHosts, maxLevel,
status.mapProgress());
if (target == -1) {
return null;
}
Task result = maps[target].getTaskToRun(tts.getTrackerName());
if (result != null) {
addRunningTaskToTIP(maps[target], result.getTaskID(), tts, true);
resetSchedulingOpportunities();
}
return result;
NON_LOCAL_CACHE_LEVEL。在findNewMapTask方法中可以看到,运行失败的任务总是被优先选择,让它们能够快速重新执行;然后按照数据本地性选择尚未运行的任务;最后是查找正在运行的任务,为较慢的任务启动备份(推测执行)。有兴趣可以看源码这里不展示了。
synchronized (jobQueue) {
for (JobInProgress job : jobQueue) {
if (job.getStatus().getRunState() != JobStatus.RUNNING ||
job.numReduceTasks == 0) {
continue;
}
Task t =
job.obtainNewReduceTask(taskTrackerStatus, numTaskTrackers,
taskTrackerManager.getNumberOfUniqueHosts()
);
if (t != null) {
assignedTasks.add(t);
break;
}
// Don't assign reduce tasks to the hilt!
// Leave some free slots in the cluster for future task-failures,
// speculative tasks etc. beyond the highest priority job
if (exceededReducePadding) {
break;
}
}
}
注意,每一次心跳只分配一个reduce任务。
最后,我们关注一下当要执行的任务获得以后,如何返回给TaskTracker,以及JobTracker下达的一些命令。
TaskTrackerAction[] actions;
这个数组就用于JobTracker向TaskTracker下达命令,包括执行刚刚选择的任务的指令。具体的命令种类有以下五种:
short newResponseId = (short)(responseId + 1);
status.setLastSeen(now);
if (!processHeartbeat(status, initialContact, now)) {
if (prevHeartbeatResponse != null) {
trackerToHeartbeatResponseMap.remove(trackerName);
}
return new HeartbeatResponse(newResponseId,
new TaskTrackerAction[] {new ReinitTrackerAction()});
}
List<Task> tasks = getSetupAndCleanupTasks(taskTrackerStatus);
if (tasks == null ) {
tasks = taskScheduler.assignTasks(taskTrackers.get(trackerName));
}
if (tasks != null) {
for (Task task : tasks) {
expireLaunchingTasks.addNewTask(task.getTaskID());
actions.add(new LaunchTaskAction(task));
}
}
// Check for tasks to be killed
List<TaskTrackerAction> killTasksList = getTasksToKill(trackerName);
if (killTasksList != null) {
actions.addAll(killTasksList);
} // Check for jobs to be killed/cleanedup
List<TaskTrackerAction> killJobsList = getJobsForCleanup(trackerName);
if (killJobsList != null) {
actions.addAll(killJobsList);
} // Check for tasks whose outputs can be saved
List<TaskTrackerAction> commitTasksList = getTasksToSave(status);
if (commitTasksList != null) {
actions.addAll(commitTasksList);
}
至此,任务调度功流程大体框架全部结束,接下来就是任务在TaskTracker上的具体执行过程了。请关注后续文章。
MapReduce调度与执行原理之任务调度(续)的更多相关文章
- MapReduce调度与执行原理之任务调度
前言 :本文旨在理清在Hadoop中一个MapReduce作业(Job)在提交到框架后的整个生命周期过程,权作总结和日后参考,如有问题,请不吝赐教.本文不涉及Hadoop的架构设计,如有兴趣请参考相关 ...
- MapReduce调度与执行原理系列文章
转自:http://blog.csdn.net/jaytalent?viewmode=contents MapReduce调度与执行原理系列文章 一.MapReduce调度与执行原理之作业提交 二.M ...
- MapReduce调度与执行原理之作业初始化
前言 :本文旨在理清在Hadoop中一个MapReduce作业(Job)在提交到框架后的整个生命周期过程,权作总结和日后参考,如有问题,请不吝赐教.本文不涉及Hadoop的架构设计,如有兴趣请参考相关 ...
- MapReduce调度与执行原理之作业提交
前言 :本文旨在理清在Hadoop中一个MapReduce作业(Job)在提交到框架后的整个生命周期过程,权作总结和日后参考,如有问题,请不吝赐教.本文不涉及Hadoop的架构设计,如有兴趣请参考相关 ...
- erlang虚拟机代码执行原理
转载:http://blog.csdn.NET/mycwq/article/details/45653897 erlang是开源的,很多人都研究过源代码.但是,从erlang代码到c代码,这是个不小 ...
- springmvc执行原理及自定义mvc框架
springmvc是spring的一部分,也是一个优秀的mvc框架,其执行原理如下: (1)浏览器提交请求经web容器(比如tomcat)转发到中央调度器dispatcherServlet. (2)中 ...
- MapReduce作业的执行流程
MapReduce任务执行总流程 一个MapReduce作业的执行流程是:代码编写 -> 作业配置 -> 作业提交 -> Map任务的分配和执行 -> 处理中间结果 -> ...
- Hadoop架构设计、执行原理具体解释
1.Map-Reduce的逻辑过程 如果我们须要处理一批有关天气的数据.其格式例如以下: 依照ASCII码存储.每行一条记录 每一行字符从0開始计数,第15个到第18个字符为年 第25个到第29个字符 ...
- Golang调度器GMP原理与调度全分析(转 侵 删)
该文章主要详细具体的介绍Goroutine调度器过程及原理,包括如下几个章节. 第一章 Golang调度器的由来 第二章 Goroutine调度器的GMP模型及设计思想 第三章 Goroutine调度 ...
随机推荐
- python OptionParser模块
Python中强大的选项处理模块. #!/usr/bin/python from optparse import OptionParser parser = OptionParser() parser ...
- BZOJ 1005 明明的烦恼 (组合数学)
题解:n为树的节点数,d[ ]为各节点的度数,m为无限制度数的节点数. 则 所以要求在n-2大小的数组中插入tot各序号,共有种插法: 在tot各序号排列中,插第一个节点的 ...
- hdu4336 Card Collector 状态压缩dp
Card Collector Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tota ...
- 十一、观察者模式(Observable、Observer)
老板出差了,员工1.员工2..均放羊中.他们请求前台的秘书,当老板回来时通知自己,免得被Boss抓个现行.秘书想了想,说————嗯,这是观察者模式. 当一个对象的改变需要同时改变其它对象,而且它不知道 ...
- 用nodejs安装hexo,将hexo部署到github
跌跌撞撞写这篇博文,希望下一篇可以好点 运行环境:最新版本的nodejs + git 安装好nodejs 和 git ,注册好github账号,新建仓库****.github.io(****为gith ...
- 【转】KVM/Installation
[转]KVM/Installation Installation Pre-installation checklist Check that your CPU supports hardware vi ...
- Visual Studio Tools for Unity安装及使用
Visual Studio Tools for Unity安装及使用 转载自:CSDN 晃了一下,10.1到现在又过去两个月了,这两个月什么也没有学,整天上班下班,从这周末开始拾起unity,为了年后 ...
- [LeetCode]题解(python):029-Divide Two Integers
题目来源: https://leetcode.com/problems/divide-two-integers/ 题意分析: 不用乘法,除法和mod运算来实现一个除法.如果数值超过了int类型那么返回 ...
- Qt 错误: 无法运行 release 下的可执行文件
学习Qt有一点时间了,但之前都是在debug版本下进行编译运行,偶然切换到release版本下,却出现了如下错误: 错误提示: This application failed to sta ...
- C++ ABI之名字改变,编译器生成符号研究(以Qt为例)
在C++中,由于重载等技术的存在,编译器要将函数.结构体.类等等的信息传递给链接器,就不能像C语言那样简单地通过函数名来完成,它需要提供额外的参数信息,而还要和C语言共用链接器,这就需要用到名字改编( ...