mapreduce job提交流程原始碼級分析(三)

玖瘋發表於2014-05-11

  mapreduce job提交流程原始碼級分析(二)(原創)這篇文章說到了jobSubmitClient.submitJob(jobId, submitJobDir.toString(), jobCopy.getCredentials())提交job,最終呼叫的是JobTracker.submitJob;而這篇文章JobTracker啟動流程原始碼級分析則是分析的JobTracker的啟動過程,JobTracker啟動之後就會等待提交作業管理作業等。

  接下來看看JobTracker.submitJob方法,呼叫這個方法之前已經將相關的資源分片資訊、配置資訊、外部檔案、第三方jar包、一些歸檔檔案以及job.jar上傳到HDFS中了。

 1  public JobStatus submitJob(JobID jobId, String jobSubmitDir, Credentials ts)
 2       throws IOException {
 3     JobInfo jobInfo = null;
 4     UserGroupInformation ugi = UserGroupInformation.getCurrentUser();
 5     synchronized (this) {
 6       if (jobs.containsKey(jobId)) {
 7         // job already running, don't start twice
 8         return jobs.get(jobId).getStatus();
 9       }
10       jobInfo = new JobInfo(jobId, new Text(ugi.getShortUserName()),
11           new Path(jobSubmitDir));
12     }
13     
14     // Create the JobInProgress, do not lock the JobTracker since
15     // we are about to copy job.xml from HDFS
16     //當JobTracker接收到新的job請求(即submitJob()函式被呼叫)後,
17     //會建立一個JobInProgress物件並通過它來管理和排程任務。
18     //JobInProgress在建立的時候會初始化一系列與任務有關的引數,呼叫到FileSystem,
19     //把在JobClient端上傳的所有任務檔案下載到本地的檔案系統中的臨時目錄裡。這其中包括上傳的*.jar檔案包、
20     //記錄配置資訊的xml、記錄分割資訊的檔案。
21     JobInProgress job = null;
22     try {
23       job = new JobInProgress(this, this.conf, jobInfo, 0, ts);
24     } catch (Exception e) {
25       throw new IOException(e);
26     }
27     
28     synchronized (this) {
29       // check if queue is RUNNING
30       String queue = job.getProfile().getQueueName();
31       if (!queueManager.isRunning(queue)) {
32         throw new IOException("Queue \"" + queue + "\" is not running");
33       }
34       try {
35         aclsManager.checkAccess(job, ugi, Operation.SUBMIT_JOB);
36       } catch (IOException ioe) {
37         LOG.warn("Access denied for user " + job.getJobConf().getUser()
38             + ". Ignoring job " + jobId, ioe);
39         job.fail();
40         throw ioe;
41       }
42 
43       // Check the job if it cannot run in the cluster because of invalid memory
44       // requirements.
45       try {
46         checkMemoryRequirements(job);
47       } catch (IOException ioe) {
48         throw ioe;
49       }
50       boolean recovered = true; // TODO: Once the Job recovery code is there,
51       // (MAPREDUCE-873) we
52       // must pass the "recovered" flag accurately.
53       // This is handled in the trunk/0.22
54       if (!recovered) {
55         // Store the information in a file so that the job can be recovered
56         // later (if at all)
57         Path jobDir = getSystemDirectoryForJob(jobId);
58         FileSystem.mkdirs(fs, jobDir, new FsPermission(SYSTEM_DIR_PERMISSION));
59         FSDataOutputStream out = fs.create(getSystemFileForJob(jobId));
60         jobInfo.write(out);
61         out.close();
62       }
63       
64       // Submit the job
65       JobStatus status;
66       try {
67         status = addJob(jobId, job);
68       } catch (IOException ioe) {
69         LOG.info("Job " + jobId + " submission failed!", ioe);
70         status = job.getStatus();
71         status.setFailureInfo(StringUtils.stringifyException(ioe));
72         failJob(job);
73         throw ioe;
74       }
75       
76       return status;
77     }
78   }

  一、首先看看jobs中有無要提交的Job,jobs是一個Map<JobID, JobInProgress> 這裡儲存著所有已知的Job及其對應的JobInProgress資訊。如果已經存在這個Job則直接返回這個Job的狀態;如果不存在則利用JobID和jobSubmitDir構造一個JobInfo物件,JobInfo類實現了Writable可以被序列化,而且儲存三個欄位JobID、user、以及上傳資源的目錄jobSubmitDir;

  二、建立一個JobInProgress物件,JobInProgress類主要用於監控和跟蹤作業執行狀態,存在於作業的整個執行過程中,併為排程器提供最底層的排程介面,維護了兩部分資訊:一種是靜態資訊這些在作業提交之時就確定好了;另一種是動態的會隨著作業的執行而動態變化的。job = new JobInProgress(this, this.conf, jobInfo, 0, ts),這裡會建立一個JobProfile一直跟蹤作業的執行,不管作業作業活著還是死了;

  三、checkMemoryRequirements(job)檢查Job是否有無效的記憶體需求而不能執行,檢查JobTracker的配置有無問題,再檢查Job的記憶體配置有無問題;

  四、是否儲存作業資訊以備恢復。在1.0.0版本中這還沒實現(在這就是沒儲存資訊),要存的資訊是一個JobInfo物件儲存著作業的儲存目錄、ID以及user。

  五、status = addJob(jobId, job)這是核心的提交方法。會將此Job放入jobs中,jobs儲存著JobTracker所有執行作業的對應關係<jobID,JobInProgress>;然後讓所有的JobInProgressListener監聽這個Job,根據JobTracker啟動流程原始碼級分析 中可以知道這些JobInProgressListener例項都是通過排程器初始化(JobQueueTaskScheduler.start()方法)時,有倆執行緒一個是監控Job生命週期的,一個是對新加入的Job初始化的;一個監控Job的整個生命週期;然後加入監控統計中,返回job狀態job.getStatus()。

 

  這樣Job的提交過程就完了,剩下的就是作業的排程分配及監控了。後續再講吧

參考:

  董西成,《Hadoop技術內幕:深入解析MapReduce架構設計與實現原理》

相關文章