客戶端MapReduce提交到YARN過程(二)

客戶端通過RPC協議ClientRMProtocol提交Application,其實是提交了一個SubmitApplicationRequest,在Hadoop 1.0時代,是使用Writable作爲序列化和反序列化框架的,而在2.0中hadoop已經廢棄掉了,改用了ProtocolBuffer,它除了支持多種語言外最大的好處是向後兼容性,這樣不同版本的AM,Client,RM和NM之間能相互通信。

比如對於SubmitApplicationRequest, 源代碼只有PB的實現SubmitApplicationRequestPBImpl,當然用戶也可以實現其他的序列化反序列化框架的實現,包括Writable實現

SubmitApplicationRequest中會封裝提交上下文信息ApplicationSubmissionContext. ClientRMProtocol在RM的實現類是ClientRMService, RM在啓動的時候會初始化這個Service,該Service負責端口監聽RPC請求(由yarn.resourcemanager.address設置)

服務端根據提交上下文信息構造RMAppManagerSubmitEvent對象,交由rmAppManager來處理,RMAppManager在RM中的作用是管理所有的Application,比如提交/完成application,恢復一組applications等等。

ClientRMService的submitApplication方法:
public SubmitApplicationResponse submitApplication(
      SubmitApplicationRequest request) throws YarnRemoteException {
		 ApplicationSubmissionContext submissionContext = request
		 .getApplicationSubmissionContext();
		 ApplicationId applicationId = submissionContext.getApplicationId();
		 String user = submissionContext.getUser();
		 user = UserGroupInformation.getCurrentUser().getShortUserName();
		 if (rmContext.getRMApps().get(applicationId) != null) {
		 throw new IOException("Application with id " + applicationId
		 + " is already present! Cannot add a duplicate!");
		 }
		 submissionContext.setUser(user);
		 // 將Application信息提交給rmAppManager來啓動ApplicationMaster
		 rmAppManager.handle(new RMAppManagerSubmitEvent(submissionContext, System
		 .currentTimeMillis()));
		 
		 // If recovery is enabled then store the application information in a 
		 // blocking call so make sure that RM has stored the information needed 
		 // to restart the AM after RM restart without further client communication
		 RMStateStore stateStore = rmContext.getStateStore();
		 LOG.info("Storing Application with id " + applicationId);
		 try {
		 stateStore.storeApplication(rmContext.getRMApps().get(applicationId));
		 } catch (Exception e) {
		 LOG.error("Failed to store application:" + applicationId, e);
		 ExitUtil.terminate(1, e);
		 }
		 LOG.info("Application with id " + applicationId.getId() + 
		 " submitted by user " + user);
		 RMAuditLogger.logSuccess(user, AuditConstants.SUBMIT_APP_REQUEST,
		 "ClientRMService", applicationId);


		 SubmitApplicationResponse response = recordFactory
		 .newRecordInstance(SubmitApplicationResponse.class);
		 return response;
}

YARN採用了基於事件驅動的編程模型,一個狀態的改變可以觸發一個或多個事件,同時可以觸發其他狀態發生變化。對於RMAppManagerSubmitEvent他有兩種狀態APP_SUBMITAPP_COMPLETED,在RMAppManager Handle這個Event的時候,如果是APP_COMPLETED則執行finishApplication將ApplicationId加入completedApps隊列中,若狀態爲APP_SUBMIT則執行submitApplication方法生成一個RMApp,放入RMContext的Map<ApplicationId, RMApp> applications總,然後生成一個狀態爲START的RMAppEvent交由AsyncDispatcher中央調度器來處理。

調用棧


RMAppManager的handle函數
  public void handle(RMAppManagerEvent event) {
    ApplicationId applicationId = event.getApplicationId();
    LOG.debug("RMAppManager processing event for " 
        + applicationId + " of type " + event.getType());
    switch(event.getType()) {
      case APP_COMPLETED: 
      {
        finishApplication(applicationId);
        ApplicationSummary.logAppSummary(
            rmContext.getRMApps().get(applicationId));
        checkAppNumCompletedLimit(); 
      } 
      break;
      case APP_SUBMIT:
      {
        ApplicationSubmissionContext submissionContext = 
            ((RMAppManagerSubmitEvent)event).getSubmissionContext();
        long submitTime = ((RMAppManagerSubmitEvent)event).getSubmitTime();
        submitApplication(submissionContext, submitTime);
      }
      break;
      default:
        LOG.error("Invalid eventtype " + event.getType() + ". Ignoring!");
      }
  }

submitApplication邏輯
 protected void submitApplication(
      ApplicationSubmissionContext submissionContext, long submitTime) {
    ApplicationId applicationId = submissionContext.getApplicationId();
    RMApp application = null;
    try {
      // Create RMApp
      application =
          new RMAppImpl(applicationId, rmContext, this.conf,
            submissionContext.getApplicationName(),
            submissionContext.getUser(), submissionContext.getQueue(),
            submissionContext, this.scheduler, this.masterService,
            submitTime);
   rmContext.getRMApps().putIfAbsent(applicationId, application) != 
          null);
      // All done, start the RMApp
      this.rmContext.getDispatcher().getEventHandler().handle(
          new RMAppEvent(applicationId, RMAppEventType.START));
    } catch (IOException ie) {
        LOG.info("RMAppManager submit application exception", ie);
        if (application != null) {
          // Sending APP_REJECTED is fine, since we assume that the 
          // RMApp is in NEW state and thus we havne't yet informed the 
          // Scheduler about the existence of the application
          this.rmContext.getDispatcher().getEventHandler().handle(
              new RMAppRejectedEvent(applicationId, ie.getMessage()));
        }
    }
  }


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章