1.job.waitForCompletion(true);
/**
* 主要是將任務提交到集羣中去並等待完成
* boolean verbose:是否將進度打印給用戶看
* return 任務成功返回true
*/
public boolean waitForCompletion(boolean verbose
) throws IOException, InterruptedException,
ClassNotFoundException {
//判斷job狀態是否爲define,避免二次提交,JobState爲枚舉:DEFINE,RUNNING
if (state == JobState.DEFINE) {
submit();//將任務提交到集羣 --> 1.1 submit()
}
if (verbose) {
monitorAndPrintJob();
} else {
// get the completion poll interval from the client.
int completionPollIntervalMillis =
Job.getCompletionPollInterval(cluster.getConf());
while (!isComplete()) {
try {
Thread.sleep(completionPollIntervalMillis);
} catch (InterruptedException ie) {
}
}
}
return isSuccessful();
}
1.1submit()
public void submit()
throws IOException, InterruptedException, ClassNotFoundException {
ensureState(JobState.DEFINE);
// 該方法做了系統兼容,避免出現框架更新,老版本無法使用
setUseNewAPI();
// 這裏面創建了一個很重要的對象,用於建立連接本地還是集羣連接 --> 1.1.1 connect()
connect();
final JobSubmitter submitter =
getJobSubmitter(cluster.getFileSystem(), cluster.getClient());
status = ugi.doAs(new PrivilegedExceptionAction<JobStatus>() {
public JobStatus run() throws IOException, InterruptedException,
ClassNotFoundException {
/* 真正開始提交job流程,準備工作終於做完了 --> JobStatus submitJobInternal(Job job, Cluster cluster)
*/
return submitter.submitJobInternal(Job.this, cluster);
}
});
state = JobState.RUNNING;
LOG.info("The url to track the job: " + getTrackingURL());
}
1.1.1 connect
private synchronized void connect()
throws IOException, InterruptedException, ClassNotFoundException {
//第一次連接的話一定爲null
if (cluster == null) {
cluster =
ugi.doAs(new PrivilegedExceptionAction<Cluster>() {
public Cluster run()
throws IOException, InterruptedException,
ClassNotFoundException {
//創建提交Job的代理 --> cluster(Configuration conf)
return new Cluster(getConfiguration());
}
});
}
}
/**
* public Cluster(Configuration conf)
* 主要作用是獲取你在Driver中Configuration配置的文件信息,沒有配置使用默認
*/
public Cluster(Configuration conf) throws IOException {
this(null, conf);
}
/**
* 調用initialize(jobTrackAddr, conf)返回的值
* jobTrackAddr:local還是yarn
* conf:配置的信息
*/
public Cluster(InetSocketAddress jobTrackAddr, Configuration conf)
throws IOException {
this.conf = conf;
this.ugi = UserGroupInformation.getCurrentUser();
initialize(jobTrackAddr, conf); // --> initialize()
}
/**
* ...表示該方法中的校驗代碼
* jobTrackAddr:狀態
* conf:配置信息
*/
private void initialize(InetSocketAddress jobTrackAddr, Configuration conf)throws IOException {
...
/*
判斷Driver裏配置狀態,如果是yarn則返回YarnRunner對象,如果沒有配置則返回LocalJobRunner對象
*/
if (jobTrackAddr == null) {
/*
第一次判斷--> public ClientProtocol create(Configuration conf)
第二次判斷--> public ClientProtocol create(Configuration conf)
*/
clientProtocol = provider.create(conf);
} else {
clientProtocol = provider.create(jobTrackAddr, conf);
}
...
}
/**
* yarn是否和Driver中配置的conf.set("mapreduce.framework.name","yarn");
* 相同,相同的話就返回一個YARNRunner對象,沒有配置的話就返回一個null,而後進行
* 第二次判斷
*/
public ClientProtocol create(Configuration conf) throws IOException {
return "yarn".equals(conf.get("mapreduce.framework.name")) ?
new YARNRunner(conf) : null;
}
/**
* 之前返回爲null的話就進行第二次判斷
*/
public ClientProtocol create(Configuration conf) throws IOException {
/*
MRConfig.FRAMEWORK_NAME:"mapreduce.framework.name"
LOCAL_FRAMEWORK_NAME:"local"
沒有這個值就獲得一個LOCAL_FRAMEWORK_NAME
*/
String framework =conf.get(MRConfig.FRAMEWORK_NAME, MRConfig.LOCAL_FRAMEWORK_NAME);
//判斷兩方是否都爲local,相同的話就創建LocalJobRunner()對象
if (!MRConfig.LOCAL_FRAMEWORK_NAME.equals(framework)) {
return null;
}
conf.setInt(JobContext.NUM_MAPS, 1);
return new LocalJobRunner(conf);
} // --> submint() --> return submitter.submitJobInternal(Job.this, cluster);
總結:connect方法最終要的地方就是,爲我們創建了一個關鍵的對象LocalJobRunner對象,這個對象爲我們之後提交作業所用,很重要。
1.1.2 提交JOB
JobStatus submitJobInternal(Job job, Cluster cluster)throws ClassNotFoundException, InterruptedException, IOException {
/*
校驗文件輸出路徑是否在Driver中配置,如果沒有配置拋出InvalidJobConfException,如果文件路徑存在拋出 FileAlreadyException
*/
checkSpecs(job);
// 獲取conf配置
Configuration conf = job.getConfiguration();
addMRFrameworkToDistributedCache(conf);
// 創建路徑,往路勁裏生成信息,提供給APPMaster使用 在集羣中也就是tem路勁
Path jobStagingArea = JobSubmissionFiles.getStagingDir(cluster, conf);
// 配置校驗信息我就用...代替了,太多容易把眼睛看花,感興趣的朋友可以用DeBug邊跳邊看裏面的具體信息。
...
// 創建jobId 也就是8088端口中 任務的id
JobID jobId = submitClient.getNewJobID();
// 獲得jobId設置到job裏
job.setJobID(jobId);
// 將jobStagingArea和jobId拼在一起,拼成一個提交信息(配置信息,切片信息,jar包)的路徑
Path submitJobDir = new Path(jobStagingArea, jobId.toString());
...
// 拷貝jar包到集羣(本地模式看不到,在向集羣提交的時候才能看到jar包)
copyAndConfigureFiles(job, submitJobDir);
// 會在submitJobDir目錄下創建一個job.xml文件
Path submitJobFile = JobSubmissionFiles.getJobConfPath(submitJobDir);
LOG.debug("Creating splits at " + jtFs.makeQualified(submitJobDir));
/* 切片,具體怎麼切,再看切片源碼的時候會提到,在執行完該方法後submitJobDir路徑中會多出split和crc 文件
*/
int maps = writeSplits(job, submitJobDir);