MapReduce提交過程
在Xshell中輸入
bash -X
命令可以在Bash shell中啟用debug模式,顯示執行過程中的詳細資訊,例如每條命令的執行結果以及執行的步驟。
-
Hadoop提交執行
-
開始使用Java命令執行 java org.apache.hadoop.util.RunJar hadoop-1.0-SNAPSHOT.jar com.shujia.mr.worcount.WordCount
-
開始執行RunJar類中的main方法
public static void main(String[] args) throws Throwable { new RunJar().run(args); => args表示Java命令執行時對應的傳參 // 引數: hadoop-1.0-SNAPSHOT.jar com.shujia.mr.worcount.WordCount }
-
開始呼叫run方法
public void run(String[] args) throws Throwable { String usage = "RunJar jarFile [mainClass] args..."; if (args.length < 1) { System.err.println(usage); System.exit(-1); } int firstArg = 0; // fileName = hadoop-1.0-SNAPSHOT.jar String fileName = args[firstArg++]; File file = new File(fileName); if (!file.exists() || !file.isFile()) { System.err.println("JAR does not exist or is not a normal file: " + file.getCanonicalPath()); System.exit(-1); } // mainClassName 主類名稱 => Hadoop jar包中要執行的具體類 String mainClassName = null; JarFile jarFile; try { jarFile = new JarFile(fileName); } catch (IOException io) { throw new IOException("Error opening job jar: " + fileName) .initCause(io); } // 獲取jar包中定義的主類 不用 Manifest manifest = jarFile.getManifest(); if (manifest != null) { mainClassName = manifest.getMainAttributes().getValue("Main-Class"); } jarFile.close(); // mainClassName在jar包中沒有定義 => maven打包 if (mainClassName == null) { if (args.length < 2) { System.err.println(usage); System.exit(-1); } // firstArg =1 => 對應 com.shujia.mr.worcount.WordCount mainClassName = args[firstArg++]; } // 類路徑的名稱 mainClassName = mainClassName.replaceAll("/", "."); // java.io.tmpdir 臨時的目錄 File tmpDir = new File(System.getProperty("java.io.tmpdir 臨時的目錄 ")); ensureDirectory(tmpDir); ... // createClassLoader 類載入器方法 ClassLoader loader = createClassLoader(file, workDir); // 透過建立的類載入器loader 可以載入給定jar包中的類 Thread.currentThread().setContextClassLoader(loader); // Class.forName 可以構建 WordCount.class的類物件 Class<?> mainClass = Class.forName(mainClassName, true, loader); // WordCount.class的類物件 getMethod透過反射的方式獲取類中的main方法 Method main = mainClass.getMethod("main", String[].class); // 將剩餘的引數包裝 再傳入 main方法中 List<String> newArgsSubList = Arrays.asList(args) .subList(firstArg, args.length); String[] newArgs = newArgsSubList .toArray(new String[newArgsSubList.size()]); // invoke可以對當前Method物件中的方法進行執行 // new Object[] {newArgs} 表示main方法中的傳參 => try { main.invoke(null, new Object[] {newArgs}); } catch (InvocationTargetException e) { throw e.getTargetException(); } }
-
開始執行自定類中的main方法 => 載入配置資訊
job.waitForCompletion(true); // 開始提交執行
-
進入waitForCompletion方法內
public boolean waitForCompletion(boolean verbose ) throws IOException, InterruptedException, ClassNotFoundException { if (state == JobState.DEFINE) { submit(); // 當程式提交了 如果是再Hadoop叢集中,是需要提交給Yarn執行 // mapreduce.JobSubmitter: Submitting tokens for job: job_1716520379305_0009 } return isSuccessful(); }
-
submit方法
public void submit() throws IOException, InterruptedException, ClassNotFoundException { ensureState(JobState.DEFINE); setUseNewAPI(); // 設定新的API => Hadoop中有一些老API存在所以需要進行設定 connect(); // 非同步建立cluster物件 在該物件中包含了有多個叢集連線資訊 => cluster 表示Yarn叢集客戶端 final JobSubmitter submitter = getJobSubmitter(cluster.getFileSystem(), cluster.getClient()); status = ugi.doAs(new PrivilegedExceptionAction<JobStatus>() { public JobStatus run() throws IOException, InterruptedException, ClassNotFoundException { // 開始正式提交任務 return submitter.submitJobInternal(Job.this, cluster); } }); state = JobState.RUNNING; LOG.info("The url to track the job: " + getTrackingURL()); }
- 注意:
- LocalJobRunner對應的是本地的資料執行
- YARNRunner是對應將資料提交到YARN上執行