Hadoop學習第四天--MapReduce提交過程

shmil發表於2024-08-10

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上執行

相關文章