mapreduce job提交流程源码级分析(三)中已经说明用户最终调用JobTracker.submitJob方法来向JobTracker提交作业。而这个方法的核心提交方法是JobTracker.addJob(JobID jobId, JobInProgress job)方法,这个addJob方法会把Job提交到调度器(默认是JobQueueTaskScheduler)的监听器JobQueueJobInProgressListener和EagerTaskInitializationListener(本文只讨论默认调度器)中,使用方法jobAdded(JobInProgress job),JobQueueJobInProgressListener任务是监控各个JobInProcess生命周期中的变化;EagerTaskInitializationListener是发现有新Job后对其初始化的。

  一、JobQueueJobInProgressListener.jobAdded(JobInProgress job)方法。就一句代码jobQueue.put(new JobSchedulingInfo(job.getStatus()), job),先构建一个JobSchedulingInfo对象,然后和JobInProgress对应起来放入jobQueue中。JobSchedulingInfo类维护这调度这个job必备的一些信息,比如优先级(默认是NORMAL)、JobID以及开始时间startTime。

  二、EagerTaskInitializationListener.jobAdded(JobInProgress job)方法。  

 /**
* We add the JIP to the jobInitQueue, which is processed
* asynchronously to handle split-computation and build up
* the right TaskTracker/Block mapping.
*/
@Override
public void jobAdded(JobInProgress job) {
synchronized (jobInitQueue) {
jobInitQueue.add(job);  //添加进List<JobInProgress> jobInitQueue
resortInitQueue();
jobInitQueue.notifyAll();  //唤醒阻塞的进程
} }

  上面方法中resortInitQueue()方法主要是对jobInitQueue中JobInProcess进行排序,先按照优先级排序,相同的再按开始时间。EagerTaskInitializationListener.start()在调度器初始化时JobQueueTaskScheduler.start()就调用了,所以先于jobAdded方法调用。EagerTaskInitializationListener.start()代码如下:

 public void start() throws IOException {
this.jobInitManagerThread = new Thread(jobInitManager, "jobInitManager");
jobInitManagerThread.setDaemon(true);
this.jobInitManagerThread.start();
}

  start()方法会启动一个线程:JobInitManager。

 /////////////////////////////////////////////////////////////////
// Used to init new jobs that have just been created
/////////////////////////////////////////////////////////////////
class JobInitManager implements Runnable { public void run() {
JobInProgress job = null;
while (true) {
try {
synchronized (jobInitQueue) {
while (jobInitQueue.isEmpty()) {
jobInitQueue.wait();
}
job = jobInitQueue.remove(0);
}
threadPool.execute(new InitJob(job));
} catch (InterruptedException t) {
LOG.info("JobInitManagerThread interrupted.");
break;
}
}
LOG.info("Shutting down thread pool");
threadPool.shutdownNow();
}
} class InitJob implements Runnable { private JobInProgress job; public InitJob(JobInProgress job) {
this.job = job;
} public void run() {
ttm.initJob(job);//对应JobTracker的对应方法
}
}

  JobInitManager线程的run方法是一个死循环始终监控jobInitQueue是否为空,不为空的话就取出0位置的JobInProgress,在InitJob线程中初始化:TaskTrackerManager.initJob(job)对应JobTracker的initJob方法。这里为什么会另起线程来初始化Job呢?原因很简单,就是可能jobInitQueue中同时会有很多JobInProgress,一个一个的初始化会比较慢,所以采用多线程的方式初始化。来看initJob方法的代码:

   public void initJob(JobInProgress job) {
if (null == job) {
LOG.info("Init on null job is not valid");
return;
} try {
JobStatus prevStatus = (JobStatus)job.getStatus().clone();
LOG.info("Initializing " + job.getJobID());
job.initTasks(); //调用该实例的initTasks方 法,对job进行初始化
// Inform the listeners if the job state has changed
// Note : that the job will be in PREP state.
JobStatus newStatus = (JobStatus)job.getStatus().clone();
if (prevStatus.getRunState() != newStatus.getRunState()) {
JobStatusChangeEvent event =
new JobStatusChangeEvent(job, EventType.RUN_STATE_CHANGED, prevStatus,
newStatus);
synchronized (JobTracker.this) {
updateJobInProgressListeners(event);
}
}
} catch (KillInterruptedException kie) {
// If job was killed during initialization, job state will be KILLED
LOG.error("Job initialization interrupted:\n" +
StringUtils.stringifyException(kie));
killJob(job);
} catch (Throwable t) {
String failureInfo =
"Job initialization failed:\n" + StringUtils.stringifyException(t);
// If the job initialization is failed, job state will be FAILED
LOG.error(failureInfo);
job.getStatus().setFailureInfo(failureInfo);
failJob(job);
}
}

  首先是获取初始化前的状态prevStatus;然后是job.initTasks()初始化;在获取初始化的后的状态newStatus;

  job.initTasks()方法代码比较多,主要的工作是检查之后获取输入数据的分片信息TaskSplitMetaInfo[] splits = createSplits(jobId)这是去读的上传到HDFS中的文件job.splitmetainfo和job.split,要确保numMapTasks == splits.length,然后构建numMapTasks个TaskInProgress作为MapTask,

MapReduce job在JobTracker初始化源码级分析的更多相关文章

  1. MapReduce的ReduceTask任务的运行源码级分析

    MapReduce的MapTask任务的运行源码级分析 这篇文章好不容易恢复了...谢天谢地...这篇文章讲了MapTask的执行流程.咱们这一节讲解ReduceTask的执行流程.ReduceTas ...

  2. MapReduce的MapTask任务的运行源码级分析

    TaskTracker任务初始化及启动task源码级分析 这篇文章中分析了任务的启动,每个task都会使用一个进程占用一个JVM来执行,org.apache.hadoop.mapred.Child方法 ...

  3. TaskTracker任务初始化及启动task源码级分析

    在监听器初始化Job.JobTracker相应TaskTracker心跳.调度器分配task源码级分析中我们分析的Tasktracker发送心跳的机制,这一节我们分析TaskTracker接受JobT ...

  4. 监听器初始化Job、JobTracker相应TaskTracker心跳、调度器分配task源码级分析

    JobTracker和TaskTracker分别启动之后(JobTracker启动流程源码级分析,TaskTracker启动过程源码级分析),taskTracker会通过心跳与JobTracker通信 ...

  5. TableInputFormat分片及分片数据读取源码级分析

    我们在MapReduce中TextInputFormat分片和读取分片数据源码级分析 这篇中以TextInputFormat为例讲解了InputFormat的分片过程以及RecordReader读取分 ...

  6. Shell主要逻辑源码级分析(1)——SHELL运行流程

    版权声明:本文由李航原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/109 来源:腾云阁 https://www.qclou ...

  7. Flume-NG内置计数器(监控)源码级分析

    Flume的内置监控怎么整?这个问题有很多人问.目前了解到的信息是可以使用Cloudera Manager.Ganglia有图形的监控工具,以及从浏览器获取json串,或者自定义向其他监控系统汇报信息 ...

  8. 源码级分析Android系统启动流程

    首先看一下Android系统的体系结构,相信大家都不陌生 1.首先Bootloader引导程序启动完Linux内核后,会加载各种驱动和数据结构,当有了驱动以后,开始启动Android系统,同时会加载用 ...

  9. Shell主要逻辑源码级分析 (2)——SHELL作业控制

    版权声明:本文由李航原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/110 来源:腾云阁 https://www.qclou ...

随机推荐

  1. maven2报xxxServlet cannot be cast to javax.servlet

    由于CacheFilter实现了javax.servlet.Filter接口,Filter是在servlet-api.jar里,因此pom中有  <dependency>          ...

  2. 疯狂Html+CSS+JS 中JS总结

    来自:http://mzkmzk.github.io/blog/2015/10/05/amazeing-js/ 0 总结 本书的JS 第一章有讲语法有挺多常见的坑点和原理解释很不错 第二章DOM编程讲 ...

  3. 【转】Spring中@Component的作用

    今天在写程序的时候看见一个以前没有见过的注解(@Component),在网上查找过后,经过实践,决定把它记录下来. 1.@controller 控制器(注入服务) 用于标注控制层,相当于struts中 ...

  4. Cookie 入门

    位于 javax.servlet.http 包下 1. HTTP 协议与 Cookie 关于 Cookie Cookie 是 HTTP 协议制定的!先由服务器保存 Cookie 到浏览器, 在下次浏览 ...

  5. XML 解析之 jaxp 解析器

    XML 的解析方式有两种方式: DOM 解析和 SAX 解析. DOM 解析: 根据 XML 的层级结构, 在内存中分配一个树形结构, 把 XML 的标签, 属性和文本都封装成对象. 优点: 可以实现 ...

  6. 借鉴+总结!! mysql 客户端命令行下 查询数据并生成文件导出

    方式1:在mysql命令行环境下执行: sql语句+INTO OUTFILE +文件路径/文件名 +编码方式(可选)  例如: select * from user  INTO OUTFILE  '/ ...

  7. Flask(4)- flask请求上下文源码解读、http聊天室单聊/群聊(基于gevent-websocket)

    一.flask请求上下文源码解读 通过上篇源码分析,我们知道了有请求发来的时候就执行了app(Flask的实例化对象)的__call__方法,而__call__方法返回了app的wsgi_app(en ...

  8. python中decorator的用法及原理(一)

    0. 概念 什么叫装饰器,其实也可以叫做包装器.即对于一个既有的函数func(args),在调用它之前和之后,我们希望都做一些事情,把这个函数包装起来. Python中的装饰器分为两类:函数装饰器和类 ...

  9. Linux学习笔记之文件权限

    前言: 说起文件权限,大家在windows下应该很熟悉就对文件右键属性,然后配置一点什么读写之类的权限,然后可以分配到每个的人. 对于linux 我先为大家介绍一个使用者和组和其他的概念说明一下 文件 ...

  10. 解决linux下python多版本兼容问题?

    环境:CentOS 7(7下默认安装python2.7) Pyhon3在CentOS中需要依赖一些其他的包,我们一次性用yum安装一下: yum install zlib-devel bzip2-de ...