对于 JobTracker 来说,主要做的事情有:
与客户端的通信:接收客户端的命令,如提交 job , kill job 。
接收 TaskTracker 心跳:为 TT 分配 Task 任务队列,更新 task 状态,以及监测 TT 的状态。
内部处理操作:
对 job 进行初始化,分解成多个 map,reduce task 任务。
对许多 job 进行排列,按照某种调度算法排列。
更新 task 的状态。
更新 job的状态 。
当 client 端调用 submitJob 方法提交 job 后,通过远程调用 Jobtracker 进程的 submitJob 方法。
Jobtracker 根据用户提交的信息,得到 jobid ,用户组及判断权限,另外将 job 的信息写到 hdfs 上,以便 TT 能够访问。
然后再调用 addJob() 方法,方法中会将 job 加入到 jobs 队列中, job 队列采用了 map 数据结构,
Map<JobID, JobInProgress> jobs = new TreeMap<JobID, JobInProgress>();
可以很方便的通过 jobid 找到该 job 相应的 JobInProgress 对象。
同时也会加入到 JobInProgressListener 类中,此类主要是用来监听 job 的类。
完成后,最后将返回 job 的状态。
synchronized JobStatus addJob(JobID jobId, JobInProgress job) { totalSubmissions ++; synchronized ( jobs ) { synchronized ( taskScheduler ) { jobs .put(job.getProfile().getJobID(), job); for ( JobInProgressListener listener : jobInProgressListeners ) { try { listener.jobAdded(job); } catch (IOException ioe) { LOG .warn( "Failed to add and so skipping the job : " + job.getJobID() + ". Exception : " + ioe); } } } } myInstrumentation .submitJob (job.getJobConf(), jobId); LOG .info( "Job " + jobId + " added successfully for user '" + job.getJobConf().getUser() + "' to queue '" + job.getJobConf().getQueueName() + "'" ); return job.getStatus(); }
|
JobInProgress 监听接口有 :
新 job 加入, job 从 JT 中去除,更新 JT 中的 job 。这几个操作都是由客户端或者 TT 发起的。
public abstract void jobAdded(JobInProgress job) throws IOException; public abstract void jobRemoved(JobInProgress job); public abstract void jobUpdated(JobChangeEvent event); |
JT 上有个 JobInProgressListener 的队列,里面有个
public void addJobInProgressListener (JobInProgressListener listener) {
jobInProgressListeners .add(listener);
}
该方法就是将相应的job 监听对象放入到JT 的监听队列上,然后由addjob 时,分别去触发这些监听对象。
而这些监听对象的加入是由 TaskScheduler 实现类通过Jobtracker addJobInProgressListener() 方法将相应的job 监听对象加入到JT 上。
TaskScheduler 是任务调度器接口,由Jobtracker 的构造函数时创建起来的。
/ Create the scheduler Class<? extends TaskScheduler> schedulerClass = conf.getClass( "mapred.jobtracker.taskScheduler" , JobQueueTaskScheduler. class , TaskScheduler. class ); taskScheduler = (TaskScheduler)ReflectionUtils.newInstance (schedulerClass, conf); |
TaskScheduler 中有个start() 方法来启动调度器中的初始化工作,包括job 监听对象,以及相应的守护线程等。
同时该类中有个变量:
protected TaskTrackerManager taskTrackerManager ;
即是jobtracker 的父类,该类包含了 TaskScheduler 调度器与Jobtracker 之间的通信,即调用接口。
而mapreduce 提供的默认的调度器是FIFO 调度类 JobQueueTaskScheduler 。
在该类的start() 方法主要:
public synchronized void start() throws IOException { super .start(); taskTrackerManager .addJobInProgressListener( jobQueueJobInProgressListener ); eagerTaskInitializationListener .setTaskTrackerManager( taskTrackerManager ); eagerTaskInitializationListener .start(); taskTrackerManager .addJobInProgressListener( eagerTaskInitializationListener ); } |
向Jobtracker 增加了二个job 监听对象。
一个是job 队列监听类,JobQueueJobInProgressListener 。
还有一个是EagerTaskInitializationListener 对job 初始化的监听类,即将job 对象转化为maptask,reducetask 对象。
接下来分析这二个类是在监听到对job 的操作后是如何处理的。
JobQueueJobInProgressListener 类中用一个队列来存放 job 。
private Map<JobSchedulingInfo, JobInProgress> jobQueue ;
此类就是将 job 加入到该队列,或者从队列中除去 job, 以及更新队列中 job 的状态。
JobQueueJobInProgressListener 中该方法如下:主要是将 job 加入到该类中的 job 队列 jobQueue 中。 jobQueue 的数据结构也是 MAP , K 为 Job 状态, V 为 job 对象。
public void jobAdded(JobInProgress job) {
jobQueue .put( new JobSchedulingInfo(job.getStatus()), job);
}
EagerTaskInitializationListener 类主要是当job 加入时,对job 进行初始化工作。在start() 方法中启动了一个初始化job 的守护线程。
线程的处理逻辑如下:对之前的 jobInitQueue 队列中的job 执行初始化。
public void start() throws IOException { this . jobInitManagerThread = new Thread( jobInitManager , "jobInitManager" ); jobInitManagerThread .setDaemon( true ); this . jobInitManagerThread .start(); } |
该守护线程主要完成job 的实始化工作,依次从队列中取出job ,进行初始化。这里利用一个线程对job 进行初始化,采用了线程池来完成多个job 的初始化。
但是在InitJob 中的线程对象调用了Jobtracker 的initJob() 方法。
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(); } } |
下面 回到addjob() 方法, 此方法如下:
public void jobAdded(JobInProgress job) {
synchronized ( jobInitQueue ) {
jobInitQueue .add(job);
resortInitQueue();
jobInitQueue .notifyAll();
}
}
同样要将job 加入到 jobInitQueue 队列中。同时计算队列中的job 的时间优先,将先来的job 放到队列前面。
未完,接下来的内容是TT与JT之间的心跳处理以及其他的job调度算法,如常用的fair schedule。
后续的内容还有TT进程分析以及HIVE各个操作的分析等。