Hadoop源码解析之ApplicationMaster启动流程

25 篇文章 0 订阅
14 篇文章 1 订阅

本文从源码调用方面介绍从应用程序提交到启动ApplicationMaster的整个过程,期间涉及ClientRMService、RMAppManager、RMAppImpl、RMAppAttemptImpl、RMNode、ResourceScheduler等几个主要组件。

当客户端调用RPC函数ApplicationClientProtocol#submitApplication之后,ResourceManager端的处理过程如下:


步骤1:

ResourceManager中的ClientRMService实现了ApplicationClientProtocol协议,它处理来自客户端的请求,并调用RMAppManager#submitApplication通知其他相关服务作进一步处理。

//clientRMService.java
public SubmitApplicationResponse submitApplication(
      SubmitApplicationRequest request) throws YarnException {
	  ...
	  
    try {
      // call RMAppManager to submit application directly
      //开始提交作业 
      rmAppManager.submitApplication(submissionContext,
          System.currentTimeMillis(), user);

      LOG.info("Application with id " + applicationId.getId() + 
          " submitted by user " + user);
      RMAuditLogger.logSuccess(user, AuditConstants.SUBMIT_APP_REQUEST,
          "ClientRMService", applicationId);
    } catch (YarnException e) {
     ...
     }
    return response;
  }

步骤2:

RMAppManager为该应用程序创建一个RMAppImpl对象以维护它的运行状态,并发送一个RMAppEventType.START事件。

//RMAppManager.java
protected void submitApplication(
      ApplicationSubmissionContext submissionContext, long submitTime,
      String user) throws YarnException {
	  
	  LOG.info("begin to submitApplication");
	  //获得作业ID
    ApplicationId applicationId = submissionContext.getApplicationId();

    //构建一个app并放入applicationACLS 
    RMAppImpl application =
        createAndPopulateNewRMApp(submissionContext, submitTime, user);
    ApplicationId appId = submissionContext.getApplicationId();

    if (UserGroupInformation.isSecurityEnabled()) {
    	...
    } else {
      // Dispatcher is not yet started at this time, so these START events
      // enqueued should be guaranteed to be first processed when dispatcher
      // gets started.
    	//触发app启动事件 
    	LOG.info("send  event RMAppEventType.START");
    	LOG.info("this.rmContext="+this.rmContext.toString());
    	//this.rmContext=RMContextImpl
      this.rmContext.getDispatcher().getEventHandler()
        .handle(new RMAppEvent(applicationId, RMAppEventType.START));
    }
  }

步骤3:

RMAppImpl收到RMAppEventType.START事件后,会调用RMStateStore#storeApplication,以日志记录RMAppImpl当前信息,

至此,RMAppImpl的运行状态由NEW转移为NEW_SAVING。该步骤就较为复杂了,下面详细介绍下。

其中RMAppEventType注册到中央异步调度器的地方在ResourceManager.java中:

//ResourceManager.java
protected void serviceInit(Configuration configuration) throws Exception {
      conf.setBoolean(Dispatcher.DISPATCHER_EXIT_ON_ERROR_KEY, true);
			...
			rmDispatcher.register(SchedulerEventType.class, schedulerDispatcher);

      // Register event handler for RmAppEvents
      rmDispatcher.register(RMAppEventType.class,
          new ApplicationEventDispatcher(rmContext));

      // Register event handler for RmAppAttemptEvents
      rmDispatcher.register(RMAppAttemptEventType.class,
          new ApplicationAttemptEventDispatcher(rmContext));

      // Register event handler for RmNodes
      rmDispatcher.register(
          RMNodeEventType.class, new NodeEventDispatcher(rmContext));
       ...
      }

上面的this.rmContext=RMContextImpl,

this.rmContext.getDispatcher()=AsyncDispatcher,

this.rmContext.getDispatcher().getEventHandler()=AsyncDispatcher$GenericEventHandler

所以会进入AsyncDispatcher类中的内部类GenericEventHandler的函数handle中

//AsyncDispatcher.java
class GenericEventHandler implements EventHandler<Event> {
    public void handle(Event event) {
    	LOG.info("begin to call GenericEventHandler::handle, event= "+event.toString());
      if (blockNewEvents) {
        return;
      }
      drained = false;

      /* all this method does is enqueue all the events onto the queue */
      int qSize = eventQueue.size();
      if (qSize !=0 && qSize %1000 == 0) {
        LOG.info("Size of event-queue is " + qSize);
      }
      int remCapacity = eventQueue.remainingCapacity();
      if (remCapacity < 1000) {
        LOG.warn("Very low remaining capacity in the event-queue: "
            + remCapacity);
      }
      try {
    	  LOG.info("begin to put event in queue.");
        eventQueue.put(event);
      } catch (InterruptedException e) {
        if (!stopped) {
          LOG.warn("AsyncDispatcher thread interrupted", e);
        }
        throw new YarnRuntimeException(e);
      }
    };
  }
handle函数里,最终把event事件放进了队列eventQueue中:eventQueue.put(event);

注意这个异步调度器AsyncDispatcher类是公用的。

RMAppEventType.START事件放入队列eventQueue中,会被RMAppImpl类获取,进入其handle函数

//RMAppImpl.java
public void handle(RMAppEvent event) {

    this.writeLock.lock();

    try {
      ApplicationId appID = event.getApplicationId();
      LOG.info("Processing event for " + appID + " of type "
          + event.getType());
      final RMAppState oldState = getState();
      try {
        /* keep the master in sync with the state machine */
        this.stateMachine.doTransition(event.getType(), event);
      } catch (InvalidStateTransitonException e) {
        LOG.error("Can't handle this event at current state", e);
        /*  fail the application on the failed transition */
      }

      if (oldState != getState()) {
        LOG.info(appID + " State change from " + oldState + " to "
            + getState());
      }
    } finally {
      this.writeLock.unlock();
    }
  }

这里面的关键语句是

this.stateMachine.doTransition(event.getType(), event);

这个stateMachine是个状态机工厂,其中绑定了很多的事件转换:

//RMAppImpl.java
private static final StateMachineFactory<RMAppImpl,
                                           RMAppState,
                                           RMAppEventType,
                                           RMAppEvent> stateMachineFactory
                               = new StateMachineFactory<RMAppImpl,
                                           RMAppState,
                                           RMAppEventType,
                                           RMAppEvent>(RMAppState.NEW)


     // Transitions from NEW state
    .addTransition(RMAppState.NEW, RMAppState.NEW,
        RMAppEventType.NODE_UPDATE, new RMAppNodeUpdateTransition())
    .addTransition(RMAppState.NEW, RMAppState.NEW_SAVING,
        RMAppEventType.START, new RMAppNewlySavingTransition())
    .addTransition(...)
    ...
    addTransition(...)
其中第二个就是

addTransition(RMAppState.NEW, RMAppState.NEW_SAVING, RMAppEventType.START, new RMAppNewlySavingTransition())

意思就是接受RMAppEventType.START类型的事件,将状态由RMAppState.NEW转换为RMAppState.NEW_SAVING,调用的回调类是RMAppNewlySavingTransition。

在addTransition函数中,就将第二个参数postState传给了新构建的内部类SingleInternalArc

//StateMachineFactory.java
public StateMachineFactory
             <OPERAND, STATE, EVENTTYPE, EVENT>
          addTransition(STATE preState, STATE postState,
                        EVENTTYPE eventType,
                        SingleArcTransition<OPERAND, EVENT> hook){
    return new StateMachineFactory<OPERAND, STATE, EVENTTYPE, EVENT>
        (this, new ApplicableSingleOrMultipleTransition<OPERAND, STATE, EVENTTYPE, EVENT>
           (preState, eventType, new SingleInternalArc(postState, hook)));
  }

初始化的内部类SingleInternalArc中,

保存了状态转换之后的值postState,此时的值就是RMAppState.NEW_SAVING。

也保存了回调函数hook=RMAppNewlySavingTransition。

//StateMachineFactory.java
SingleInternalArc(STATE postState,
        SingleArcTransition<OPERAND, EVENT> hook) {
      this.postState = postState;
      this.hook = hook;
    }

返回到RMAppImpl类的handle函数中,调用this.stateMachine.doTransition(event.getType(), event):

进入到StateMachineFactory类中

//StateMachineFactory.java
public synchronized STATE doTransition(EVENTTYPE eventType, EVENT event)
         throws InvalidStateTransitonException  {
    	LOG.info("StateMachineFactory::InternalStateMachine::doTransition 1111");
      currentState = StateMachineFactory.this.doTransition
          (operand, currentState, eventType, event);
      return currentState;
    }

再调用到

//StateMachineFactory.java
private STATE doTransition
           (OPERAND operand, STATE oldState, EVENTTYPE eventType, EVENT event)
      throws InvalidStateTransitonException {
	  LOG.info("StateMachineFactory::doTransition 2222");
	  LOG.info("operand="+operand.toString()+",oldState="+oldState.toString());
    // We can assume that stateMachineTable is non-null because we call
    //  maybeMakeStateMachineTable() when we build an InnerStateMachine ,
    //  and this code only gets called from inside a working InnerStateMachine .
    Map<EVENTTYPE, Transition<OPERAND, STATE, EVENTTYPE, EVENT>> transitionMap
      = stateMachineTable.get(oldState);
    if (transitionMap != null) {
      Transition<OPERAND, STATE, EVENTTYPE, EVENT> transition
          = transitionMap.get(eventType);
      if (transition != null) {
    	  LOG.info("transition="+transition.toString());
        return transition.doTransition(operand, oldState, event, eventType);
      }
    }
    throw new InvalidStateTransitonException(oldState, eventType);
  }

到return transition.doTransition(operand, oldState, event, eventType);

其中oldState=NEW,

transition=org.apache.hadoop.yarn.state.StateMachineFactory$SingleInternalArc@3eca92d3
进入内部类SingleInternalArc的函数doTransition中

//StateMachineFactory.java
private class SingleInternalArc
                    implements Transition<OPERAND, STATE, EVENTTYPE, EVENT> {
	  ...
    @Override
    public STATE doTransition(OPERAND operand, STATE oldState,
                              EVENT event, EVENTTYPE eventType) {
      if (hook != null) {
    	  LOG.info("SingleInternalArc::doTransition, hook = "+hook.toString());
        hook.transition(operand, event);
      }
      return postState;
    }
  }
此处调用的hook.transition(operand, event);

返回值return postState;就是上面保存的RMAppState.NEW_SAVING,到上层保存在变量currentState里,这个变量在RMAppImpl中被get函数getState()获取,

//RMAppImpl.java
if (oldState != getState()) {
        LOG.info(appID + " State change from " + oldState + " to "
            + getState());
      }
打印出来状态由 NEW 转变成 NEW_SAVING

2017-02-20 22:59:07,702 INFO org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMAppImpl: application_1487602693580_0001 State change from NEW to NEW_SAVING

此时就完成了一次状态机的状态转变。

再回到hook变量,hook初始化的就是上面状态机绑定的回调类RMAppNewlySavingTransition。
再次回调到了RMAppImpl类中的内部类RMAppNewlySavingTransition的transition函数里。

//RMAppImpl.java
private static final class RMAppNewlySavingTransition extends RMAppTransition {
    @Override
    public void transition(RMAppImpl app, RMAppEvent event) {

      // If recovery is enabled then store the application information in a
      // non-blocking call so make sure that RM has stored the information
      // needed to restart the AM after RM restart without further client
      // communication
      LOG.info("RMAppNewlySavingTransition::transition  Storing application with id " + app.applicationId);
      //app.rmContext=RMContextImpl
      LOG.info("RMAppNewlySavingTransition::transition  app.rmContext="+app.rmContext.toString());
      //app.rmContext.getStateStore()=RMStateStore
      LOG.info("RMAppNewlySavingTransition::transition  app.rmContext.getStateStore()="+app.rmContext.getStateStore().toString());
      app.rmContext.getStateStore().storeNewApplication(app);
    }
  }

其中,

app.rmContext=RMContextImpl

app.rmContext.getStateStore()=RMStateStore

进入RMStateStore类的storeNewApplication函数里

//RMStateStore.java
public synchronized void storeNewApplication(RMApp app) {
    //app=RMAppImpl
    LOG.info("begin to storeNewApplication,app="+app.toString());
    ApplicationSubmissionContext context = app.getApplicationSubmissionContext();
    assert context instanceof ApplicationSubmissionContextPBImpl;
    ApplicationState appState =
        new ApplicationState(app.getSubmitTime(), app.getStartTime(), context,app.getUser());
    dispatcher.getEventHandler().handle(new RMStateStoreAppEvent(appState));
  }
handle函数的参数new RMStateStoreAppEvent(appState),初始化了一个RMStateStoreEventType.STORE_APP事件

//RMStateStoreAppEvent.java
public RMStateStoreAppEvent(ApplicationState appState) {
    super(RMStateStoreEventType.STORE_APP);
    this.appState = appState;
  }

此处的dispatcher是RMStateStore类自己的变量,只在初始化时绑定了一个RMStateStoreEventType:

//RMStateStore.java
protected void serviceInit(Configuration conf) throws Exception{
    // create async handler
    dispatcher = new AsyncDispatcher();
    dispatcher.init(conf);
    dispatcher.register(RMStateStoreEventType.class, new ForwardingEventHandler());
    dispatcher.setDrainEventsOnStop();
    initInternal(conf);
  }
调用的类是ForwardingEventHandler:

//RMStateStore.java
private final class ForwardingEventHandler implements EventHandler<RMStateStoreEvent> {
    @Override
    public void handle(RMStateStoreEvent event) {
    	LOG.info("ForwardingEventHandler::handle ");
      handleStoreEvent(event);
    }
  }

其中的handle函数调用了函数handleStoreEvent:

//RMStateStore.java
protected void handleStoreEvent(RMStateStoreEvent event) {
    try {
    	LOG.info("handleStoreEvent,event.getType()="+event.getType().toString()+", event="+event.toString());
      this.stateMachine.doTransition(event.getType(), event);
    } catch (InvalidStateTransitonException e) {
      LOG.error("Can't handle this event at current state", e);
    }
  }

又会进入类StateMachineFactory中的内部类SingleInternalArc里,

不过这次的状态机工厂是RMStateStore类的内部变量,上面的状态机工厂是RMAppImpl类的,他们绑定的事件不同。

//RMStateStore.java
private static final StateMachineFactory<RMStateStore,
                                           RMStateStoreState,
                                           RMStateStoreEventType, 
                                           RMStateStoreEvent>
      stateMachineFactory = new StateMachineFactory<RMStateStore,
                                                    RMStateStoreState,
                                                    RMStateStoreEventType,
                                                    RMStateStoreEvent>(
      RMStateStoreState.DEFAULT)
      .addTransition(RMStateStoreState.DEFAULT, RMStateStoreState.DEFAULT,
          RMStateStoreEventType.STORE_APP, new StoreAppTransition())
      .addTransition(RMStateStoreState.DEFAULT, RMStateStoreState.DEFAULT,
          RMStateStoreEventType.UPDATE_APP, new UpdateAppTransition())
      .addTransition(RMStateStoreState.DEFAULT, RMStateStoreState.DEFAULT,
          RMStateStoreEventType.REMOVE_APP, new RemoveAppTransition())
      .addTransition(RMStateStoreState.DEFAULT, RMStateStoreState.DEFAULT,
          RMStateStoreEventType.STORE_APP_ATTEMPT, new StoreAppAttemptTransition())
      .addTransition(RMStateStoreState.DEFAULT, RMStateStoreState.DEFAULT,
          RMStateStoreEventType.UPDATE_APP_ATTEMPT, new UpdateAppAttemptTransition());

RMStateStoreEventType.STORE_APP事件只是将状态RMStateStoreState.DEFAULT再转变为自身。RMStateStoreState本事也只有一个状态DEFAULT。

主要作用就是完成RMAppImpl类当前信息的日志记录。日记记录是为了RM的重启,详情见ResourceManager重启过程

RMStateStoreEventType.STORE_APP事件绑定的类是StoreAppTransition,在StateMachineFactory中的内部类SingleInternalArc里调用hook.transition(operand, event);

就会回到RMStateStore中的内部类StoreAppTransition里的函数transition中。

//RMStateStore.java
private static class StoreAppTransition
      implements SingleArcTransition<RMStateStore, RMStateStoreEvent> {
    @Override
    public void transition(RMStateStore store, RMStateStoreEvent event) {
    	LOG.info("StoreAppTransition :: transition,event="+event.toString());
      if (!(event instanceof RMStateStoreAppEvent)) {
        // should never happen
        LOG.error("Illegal event type: " + event.getClass());
        return;
      }
      ApplicationState appState = ((RMStateStoreAppEvent) event).getAppState();
      ApplicationId appId = appState.getAppId();
      ApplicationStateData appStateData = ApplicationStateData
          .newInstance(appState);
      LOG.info("Storing info for app: " + appId);
      try {
        store.storeApplicationStateInternal(appId, appStateData);
        store.notifyDoneStoringApplication(appId, null);
      } catch (Exception e) {
        LOG.error("Error storing app: " + appId, e);
        store.notifyStoreOperationFailed(e);
      }
    };
  }

步骤4:

日志记录完成后,RMStateStore进一步向RMAppImpl发送RMAppEventType.APP_NEW_SAVED事件。

上一步中,调用 store.notifyDoneStoringApplication(appId, null);

//RMStateStore.java
private void notifyDoneStoringApplication(ApplicationId appId,Exception storedException) {
    LOG.info("notifyDoneStoringApplication, send RMAppEventType.APP_NEW_SAVED");
    rmDispatcher.getEventHandler().handle(new RMAppNewSavedEvent(appId, storedException));
  }
向中央调度器发送了一个RMAppNewSavedEvent事件:

//RMAppNewSavedEvent.java
public RMAppNewSavedEvent(ApplicationId appId, Exception storedException) {
    super(appId, RMAppEventType.APP_NEW_SAVED);
    this.storedException = storedException;
  }

事件类型是RMAppEventType.APP_NEW_SAVED,

由于在ResourceManager中,将RMAppEventType类型的事件绑定到了ApplicationEventDispatcher中:

//ResourceManager.java
// Register event handler for RmAppEvents
      rmDispatcher.register(RMAppEventType.class,new ApplicationEventDispatcher(rmContext));
所以和前面的 RMAppEventType.START事件一样,会被RMAppImpl类处理。

步骤5:

RMAppImpl收到RMAppEventType.APP_NEW_SAVED事件后,将自身的运行状态由NEW_SAVING转换为SUBMITTED ,同时向scheduler发送一个SchedulerEventType.APP_ADDED事件, 

//RMAppImpl.java
.addTransition(RMAppState.NEW_SAVING, RMAppState.SUBMITTED,
        RMAppEventType.APP_NEW_SAVED, new AddApplicationToSchedulerTransition())
进入内部类AddApplicationToSchedulerTransition中:

//RMAppImpl.java
private static final class AddApplicationToSchedulerTransition extends
      RMAppTransition {
    @Override
    public void transition(RMAppImpl app, RMAppEvent event) {
      if (event instanceof RMAppNewSavedEvent) {
    	  LOG.info("AddApplicationToSchedulerTransition::transition event="+event.toString());
        RMAppNewSavedEvent storeEvent = (RMAppNewSavedEvent) event;
        // For HA this exception needs to be handled by giving up
        // master status if we got fenced
        if (((RMAppNewSavedEvent) event).getStoredException() != null) {
          LOG.error(
            "Failed to store application: " + storeEvent.getApplicationId(),
            storeEvent.getStoredException());
          ExitUtil.terminate(1, storeEvent.getStoredException());
        }
      }
      app.handler.handle(new AppAddedSchedulerEvent(app.applicationId,
        app.submissionContext.getQueue(), app.user));
    }
  }
新建的事件类AppAddedSchedulerEvent:

//AppAddedSchedulerEvent.java
public AppAddedSchedulerEvent(
      ApplicationId applicationId, String queue, String user) {
    super(SchedulerEventType.APP_ADDED);
    this.applicationId = applicationId;
    this.queue = queue;
    this.user = user;
  }

步骤6:

scheduler收到SchedulerEventType.APP_ADDED事件之后,首先进行权限检查,然后将应用程序信息保存到内部的数据结构中,

并向RMAppImpl发送APP_ACCEPTED事件。

在ResourceManager中,SchedulerEventType事件类注册到了schedulerDispatcher类中:

//ResourceManager.java
schedulerDispatcher = createSchedulerEventDispatcher();
addIfService(schedulerDispatcher);
rmDispatcher.register(SchedulerEventType.class, schedulerDispatcher);
进入createSchedulerEventDispatcher:

//ResourceManager.java
protected EventHandler<SchedulerEvent> createSchedulerEventDispatcher() {
    return new SchedulerEventDispatcher(this.scheduler);
  }
发现传入的调度器scheduler是this.scheduler,查看this.scheduler初始化的地方:

//ResourceManager.java
// Initialize the scheduler
   scheduler = createScheduler();
   scheduler.setRMContext(rmContext);
   addIfService(scheduler);
   rmContext.setScheduler(scheduler);
再进入createScheduler函数
//ResourceManager.java
protected ResourceScheduler createScheduler() {
    String schedulerClassName = conf.get(YarnConfiguration.RM_SCHEDULER,
        YarnConfiguration.DEFAULT_RM_SCHEDULER);
    LOG.info("Using Scheduler: " + schedulerClassName);
    try {
      Class<?> schedulerClazz = Class.forName(schedulerClassName);
      if (ResourceScheduler.class.isAssignableFrom(schedulerClazz)) {
        return (ResourceScheduler) ReflectionUtils.newInstance(schedulerClazz,
            this.conf);
      } else {
        throw new YarnRuntimeException("Class: " + schedulerClassName
            + " not instance of " + ResourceScheduler.class.getCanonicalName());
      }
    } catch (ClassNotFoundException e) {
      throw new YarnRuntimeException("Could not instantiate Scheduler: "
          + schedulerClassName, e);
    }
  }
发现用的默认调度器是YarnConfiguration.DEFAULT_RM_SCHEDULER

取值为org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler

进入CapacityScheduler类中

//CapacityScheduler.java
public void handle(SchedulerEvent event) {
    switch(event.getType()) {
    ...
    case APP_ADDED:
    {
      AppAddedSchedulerEvent appAddedEvent = (AppAddedSchedulerEvent) event;
      addApplication(appAddedEvent.getApplicationId(),
        appAddedEvent.getQueue(), appAddedEvent.getUser());
    }
    break;
    ...
}
进入函数addApplication:

//CapacityScheduler.java
private synchronized void addApplication(ApplicationId applicationId,
      String queueName, String user) {
	  LOG.info("begin to call addApplication");
    // santiy checks.
    CSQueue queue = getQueue(queueName);
    if (queue == null) {
      String message = "Application " + applicationId + 
      " submitted by user " + user + " to unknown queue: " + queueName;
      this.rmContext.getDispatcher().getEventHandler()
          .handle(new RMAppRejectedEvent(applicationId, message));
      return;
    }
    if (!(queue instanceof LeafQueue)) {
      String message = "Application " + applicationId + 
          " submitted by user " + user + " to non-leaf queue: " + queueName;
      this.rmContext.getDispatcher().getEventHandler()
          .handle(new RMAppRejectedEvent(applicationId, message));
      return;
    }
    // Submit to the queue
    try {
      queue.submitApplication(applicationId, user, queueName);
    } catch (AccessControlException ace) {
      LOG.info("Failed to submit application " + applicationId + " to queue "
          + queueName + " from user " + user, ace);
      this.rmContext.getDispatcher().getEventHandler()
          .handle(new RMAppRejectedEvent(applicationId, ace.toString()));
      return;
    }
    SchedulerApplication<FiCaSchedulerApp> application =
        new SchedulerApplication<FiCaSchedulerApp>(queue, user);
    applications.put(applicationId, application);
    LOG.info("Accepted application " + applicationId + " from user: " + user
        + ", in queue: " + queueName);
    rmContext.getDispatcher().getEventHandler()
        .handle(new RMAppEvent(applicationId, RMAppEventType.APP_ACCEPTED));
  }

最后向RMAppImpl发送了RMAppEventType.APP_ACCEPTED事件。


步骤7:

RMAppImpl接受到RMAppEventType.APP_ACCEPTED事件后,将状态从SUBMITTED转换到ACCEPTED。

//RMAppImpl.java
.addTransition(RMAppState.SUBMITTED, RMAppState.ACCEPTED,
        RMAppEventType.APP_ACCEPTED, new StartAppAttemptTransition())
进入内部类StartAppAttemptTransition

//RMAppImpl.java
private static final class StartAppAttemptTransition extends RMAppTransition {
    @Override
    public void transition(RMAppImpl app, RMAppEvent event) {
    	LOG.info("class::StartAppAttemptTransition, func::transition,   ");
      app.createAndStartNewAttempt(false);
    };
  }
进入函数createAndStartNewAttempt

//RMAppImpl.java
private void
      createAndStartNewAttempt(boolean transferStateFromPreviousAttempt) {
	  LOG.info("func::createAndStartNewAttempt,begin ");
    createNewAttempt();
    handler.handle(new RMAppStartAttemptEvent(currentAttempt.getAppAttemptId(),
      transferStateFromPreviousAttempt));
  }

createNewAttempt()函数创建了一个运行实例对象RMAppAttemptImpl,并向它发送了一个RMAppAttemptEventType.START事件。

//RMAppStartAttemptEvent.java
public RMAppStartAttemptEvent(ApplicationAttemptId appAttemptId,
      boolean transferStateFromPreviousAttempt) {
    super(appAttemptId, RMAppAttemptEventType.START);
    this.transferStateFromPreviousAttempt = transferStateFromPreviousAttempt;
  }


步骤8:

RMAppAttemptImpl接受RMAppAttemptEventType.START事件后,进行一系列初始化工作。

在类RMAppAttemptImpl中,也有状态机工厂:

//RMAppAttemptImpl.java
.addTransition(RMAppAttemptState.NEW, RMAppAttemptState.SUBMITTED,
          RMAppAttemptEventType.START, new AttemptStartedTransition())
接受RMAppAttemptEventType.START事件,将自身状态由NEW转换为SUBMITTED,并调用AttemptStartedTransition:

//RMAppAttemptImpl.java
private static final class AttemptStartedTransition extends BaseTransition {
	@Override
    public void transition(RMAppAttemptImpl appAttempt,
        RMAppAttemptEvent event) {

		LOG.info("class::AttemptStartedTransition, func::transition, begin. ");
	    boolean transferStateFromPreviousAttempt = false;
      if (event instanceof RMAppStartAttemptEvent) {
        transferStateFromPreviousAttempt =
            ((RMAppStartAttemptEvent) event)
              .getTransferStateFromPreviousAttempt();
      }
      appAttempt.startTime = System.currentTimeMillis();

      // Register with the ApplicationMasterService
      appAttempt.masterService
          .registerAppAttempt(appAttempt.applicationAttemptId);

      if (UserGroupInformation.isSecurityEnabled()) {
        appAttempt.clientTokenMasterKey =
            appAttempt.rmContext.getClientToAMTokenSecretManager()
              .createMasterKey(appAttempt.applicationAttemptId);
      }

      // create AMRMToken
      AMRMTokenIdentifier id =
          new AMRMTokenIdentifier(appAttempt.applicationAttemptId);
      appAttempt.amrmToken =
          new Token<AMRMTokenIdentifier>(id,
            appAttempt.rmContext.getAMRMTokenSecretManager());

      // Add the applicationAttempt to the scheduler and inform the scheduler
      // whether to transfer the state from previous attempt.
      LOG.info("send SchedulerEventType.APP_ATTEMPT_ADDED");
      appAttempt.eventHandler.handle(new AppAttemptAddedSchedulerEvent(
        appAttempt.applicationAttemptId, transferStateFromPreviousAttempt));
    }
  }
最后发送了一个SchedulerEventType.APP_ATTEMPT_ADDED事件。

步骤9:

CapacityScheduler收到SchedulerEventType.APP_ATTEMPT_ADDED事件后,

走到默认调度器CapacityScheduler中的handle函数:

//CapacityScheduler.java
public void handle(SchedulerEvent event) {
    switch(event.getType()) {
    ...
    case APP_ATTEMPT_ADDED:
    {
      AppAttemptAddedSchedulerEvent appAttemptAddedEvent =
          (AppAttemptAddedSchedulerEvent) event;
      addApplicationAttempt(appAttemptAddedEvent.getApplicationAttemptId(),
        appAttemptAddedEvent.getTransferStateFromPreviousAttempt(),
        appAttemptAddedEvent.getShouldNotifyAttemptAdded());
    }
    break;
    ...
}
进入函数addApplicationAttempt:

//CapacityScheduler.java
private synchronized void addApplicationAttempt(
      ApplicationAttemptId applicationAttemptId,
      boolean transferStateFromPreviousAttempt,
      boolean shouldNotifyAttemptAdded) {
      LOG.info("func::addApplicationAttempt, begin.");
    SchedulerApplication<FiCaSchedulerApp> application =
        applications.get(applicationAttemptId.getApplicationId());
    CSQueue queue = (CSQueue) application.getQueue();

    FiCaSchedulerApp attempt =
        new FiCaSchedulerApp(applicationAttemptId, application.getUser(),
          queue, queue.getActiveUsersManager(), rmContext);
    if (transferStateFromPreviousAttempt) {
      attempt.transferStateFromPreviousAttempt(application
        .getCurrentAppAttempt());
    }
    application.setCurrentAppAttempt(attempt);

    queue.submitApplicationAttempt(attempt, application.getUser());
    LOG.info("Added Application Attempt " + applicationAttemptId
        + " to scheduler from user " + application.getUser() + " in queue "
        + queue.getQueueName());
    if (shouldNotifyAttemptAdded) {
      rmContext.getDispatcher().getEventHandler().handle(
          new RMAppAttemptEvent(applicationAttemptId,
              RMAppAttemptEventType.ATTEMPT_ADDED));
    } else {
      if (LOG.isDebugEnabled()) {
        LOG.debug("Skipping notifying ATTEMPT_ADDED");
      }
    }
  }

将运行实例加入到队列中:

queue.submitApplicationAttempt(attempt, application.getUser());
并打印:

Added Application Attempt appattempt_1487944669971_0001_000001 to scheduler from user root in queue default
最后发送事件RMAppAttemptEventType.ATTEMPT_ADDED给RMAppAttemptImpl。

步骤10:

RMAppAttemptImpl接受到事件RMAppAttemptEventType.ATTEMPT_ADDED后,

//RMAppAttemptImpl.java
.addTransition(RMAppAttemptState.SUBMITTED, 
          EnumSet.of(RMAppAttemptState.LAUNCHED_UNMANAGED_SAVING,
                     RMAppAttemptState.SCHEDULED),
          RMAppAttemptEventType.ATTEMPT_ADDED,
          new ScheduleTransition())
状态由SUBMITTED转换为SCHEDULED。

进入内部类ScheduleTransition的transition函数:

//RMAppAttemptImpl.java
private static final class ScheduleTransition
      implements
      MultipleArcTransition<RMAppAttemptImpl, RMAppAttemptEvent, RMAppAttemptState> {
    @Override
    public RMAppAttemptState transition(RMAppAttemptImpl appAttempt,
        RMAppAttemptEvent event) {
    	LOG.info("class::ScheduleTransition, func::transition, begin.");
      if (!appAttempt.submissionContext.getUnmanagedAM()) {
        // Request a container for the AM.
        ResourceRequest request =
            BuilderUtils.newResourceRequest(
                AM_CONTAINER_PRIORITY, ResourceRequest.ANY, appAttempt
                    .getSubmissionContext().getResource(), 1);

        // SchedulerUtils.validateResourceRequests is not necessary because
        // AM resource has been checked when submission
        Allocation amContainerAllocation = appAttempt.scheduler.allocate(
            appAttempt.applicationAttemptId,
            Collections.singletonList(request), EMPTY_CONTAINER_RELEASE_LIST, null, null);
        if (amContainerAllocation != null
            && amContainerAllocation.getContainers() != null) {
          assert (amContainerAllocation.getContainers().size() == 0);
        }
        return RMAppAttemptState.SCHEDULED;
      } else {
        // save state and then go to LAUNCHED state
        appAttempt.storeAttempt();
        return RMAppAttemptState.LAUNCHED_UNMANAGED_SAVING;
      }
    }
  }

为AM申请container资源,该资源描述如下:

ResourceRequest request =
            BuilderUtils.newResourceRequest(
                AM_CONTAINER_PRIORITY, ResourceRequest.ANY, appAttempt
                    .getSubmissionContext().getResource(), 1);
即一个优先级为AM_CONTAINER_PRIORITY(值为0),可在任意节点上ResourceRequest.ANY,

资源量为X(appAttempt .getSubmissionContext().getResource(),用户提交应用程序时指定的)的Container。


步骤11:

ResourceManager为应用程序的AM分配资源后,创建一个RMContainerImpl,并向它发送一个RMContainerEventType.START事件。

步骤12:

RMContainerImpl收到RMContainerEventType.START事件后,直接向RMAppAttemptImpl发送一个RMAppAttemptEventType.CONTAINER_ALLOCATED

事件,至此,RMContainerImpl的状态由NEW转换为ALLOCATED。

步骤13:

RMAppAttemptImpl收到RMAppAttemptEventType.CONTAINER_ALLOCATED事件后:

//RMAppAttemptImpl.java
.addTransition(RMAppAttemptState.SCHEDULED,
          EnumSet.of(RMAppAttemptState.ALLOCATED_SAVING,
            RMAppAttemptState.SCHEDULED),
          RMAppAttemptEventType.CONTAINER_ALLOCATED,
          new AMContainerAllocatedTransition())
调用AMContainerAllocatedTransition:

//RMAppAttemptImpl.java
private static final class AMContainerAllocatedTransition
      implements
      MultipleArcTransition<RMAppAttemptImpl, RMAppAttemptEvent, RMAppAttemptState> {
    @Override
    public RMAppAttemptState transition(RMAppAttemptImpl appAttempt,
        RMAppAttemptEvent event) {
      // Acquire the AM container from the scheduler.
      Allocation amContainerAllocation =
          appAttempt.scheduler.allocate(appAttempt.applicationAttemptId,
            EMPTY_CONTAINER_REQUEST_LIST, EMPTY_CONTAINER_RELEASE_LIST, null,
            null);
      // There must be at least one container allocated, because a
      // CONTAINER_ALLOCATED is emitted after an RMContainer is constructed,
      // and is put in SchedulerApplication#newlyAllocatedContainers.

      // Note that YarnScheduler#allocate is not guaranteed to be able to
      // fetch it since container may not be fetchable for some reason like
      // DNS unavailable causing container token not generated. As such, we
      // return to the previous state and keep retry until am container is
      // fetched.
      if (amContainerAllocation.getContainers().size() == 0) {
        appAttempt.retryFetchingAMContainer(appAttempt);
        return RMAppAttemptState.SCHEDULED;
      }

      // Set the masterContainer
      appAttempt.setMasterContainer(amContainerAllocation.getContainers()
          .get(0));
      RMContainerImpl rmMasterContainer = (RMContainerImpl)appAttempt.scheduler
          .getRMContainer(appAttempt.getMasterContainer().getId());
      rmMasterContainer.setAMContainer(true);
      // The node set in NMTokenSecrentManager is used for marking whether the
      // NMToken has been issued for this node to the AM.
      // When AM container was allocated to RM itself, the node which allocates
      // this AM container was marked as the NMToken already sent. Thus,
      // clear this node set so that the following allocate requests from AM are
      // able to retrieve the corresponding NMToken.
      appAttempt.rmContext.getNMTokenSecretManager()
        .clearNodeSetForAttempt(appAttempt.applicationAttemptId);
      appAttempt.getSubmissionContext().setResource(
        appAttempt.getMasterContainer().getResource());
      appAttempt.storeAttempt();
      return RMAppAttemptState.ALLOCATED_SAVING;
    }
  }

transition函数中,调用scheduler.allocate获取分配的资源,scheduler返回资源之前,会向RMContainerImpl发送

RMContainerEventType.ALLOCATED事件。

RMAppAttemptImpl收到资源后,向RMStateStore发送MStateStoreEventType.STORE_APP_ATTEMPT事件请求记录日志。

至此,RMAppAttemptImpl状态从SCHEDULED 转换为 ALLOCATED_SAVING。


步骤14:

日志记录完成后,RMStateStore向RMAppAttemptImpl发送RMAppAttemptEventType.ATTEMPT_NEW_SAVED事件。


步骤15:

RMAppAttemptImpl收到RMAppAttemptEventType.ATTEMPT_NEW_SAVED事件后,向ApplicationMasterLauncher

发送AMLauncherEventType.LAUNCH事件,至此,RMAppAttemptImpl状态从ALLOCATED_SAVING转换为ALLOCATED。


步骤16:

ApplicationMasterLauncher收到AMLauncherEventType.LAUNCH事件后,

//ApplicationMasterLauncher.java
public synchronized void  handle(AMLauncherEvent appEvent) {
    AMLauncherEventType event = appEvent.getType();
    RMAppAttempt application = appEvent.getAppAttempt();
    switch (event) {
    case LAUNCH:
      launch(application);
      break;
    case CLEANUP:
      cleanup(application);
    default:
      break;
    }
  }
//ApplicationMasterLauncher.java
private void launch(RMAppAttempt application) {
    Runnable launcher = createRunnableLauncher(application, 
        AMLauncherEventType.LAUNCH);
    masterEvents.add(launcher);
  }

调用launch函数,将该事件放入事件队列masterEvents中,

//ApplicationMasterLauncher.java
private final BlockingQueue<Runnable> masterEvents
    = new LinkedBlockingQueue<Runnable>();

等待AMLauncher线程池中的线程处理该事件

//ApplicationMasterLauncher.java
private class LauncherThread extends Thread {
    
    public LauncherThread() {
      super("ApplicationMaster Launcher");
    }

    @Override
    public void run() {
      while (!this.isInterrupted()) {
        Runnable toLaunch;
        try {
          toLaunch = masterEvents.take();
          launcherPool.execute(toLaunch);
        } catch (InterruptedException e) {
          LOG.warn(this.getClass().getName() + " interrupted. Returning.");
          return;
        }
      }
    }
  }  
处理方法是,与对应的NodeManager通信,启动AM,一旦成功启动,将进一步向RMAppAttemptImpl发送RMAppAttemptEventType.LAUNCHED事件。

RMAppAttemptImpl收到RMAppAttemptEventType.LAUNCHED事件后,会向AMLivelinessMonitor注册,以监控运行状态:

//RMAppAttemptImpl.java
private static class AMLaunchedTransition extends BaseTransition {
    @Override
    public void transition(RMAppAttemptImpl appAttempt,
                            RMAppAttemptEvent event) {
      // Register with AMLivelinessMonitor
      appAttempt.attemptLaunched();

      // register the ClientTokenMasterKey after it is saved in the store,
      // otherwise client may hold an invalid ClientToken after RM restarts.
      appAttempt.rmContext.getClientToAMTokenSecretManager()
      .registerApplication(appAttempt.getAppAttemptId(),
        appAttempt.getClientTokenMasterKey());
    }
  }

至此,RMAppAttemptImpl的状态从ALLOCATED转换为LAUNCHED。

步骤17:

NodeManager通过心跳机制汇报AM所在Container已经成功启动,收到该消息后,scheduler将发送一个RMContainerEventType.LAUNCHED

事件,RMContainerImpl收到该事件后,会从containerAllocationExpirer监控列表中移除。

//RMContainerImpl.java
// Transitions from ACQUIRED state
    .addTransition(RMContainerState.ACQUIRED, RMContainerState.RUNNING,
        RMContainerEventType.LAUNCHED, new LaunchedTransition())

//RMContainerImpl.java
private static final class LaunchedTransition extends BaseTransition {

    @Override
    public void transition(RMContainerImpl container, RMContainerEvent event) {
      // Unregister from containerAllocationExpirer.
      container.containerAllocationExpirer.unregister(container
          .getContainerId());
    }
  }

步骤18:

启动的AM通过RPC函数ApplicationMasterProtocol#registerApplicationMaster向RM注册,RM中的ApplicationMasterService服务

接收到该请求后,将向RMAppAttemptImpl发送一个RMAppAttemptEventType.REGISTERED事件,而RMAppAttemptImpl收到该事件后,

首先保存该AM的基本信息,然后向RMAppImpl发送RMAppEventType.ATTEMPT_REGISTERED,

至此,RMAppAttemptImpl状态从LAUNCHED转换为LAUNCHED。


步骤19:

RMAppImpl接受到RMAppEventType.ATTEMPT_REGISTERED后,只将状态从ACCEPTED转换为RUNNING:

//RMAppImpl.java
.addTransition(RMAppState.ACCEPTED, RMAppState.RUNNING,
        RMAppEventType.ATTEMPT_REGISTERED)


完。




















  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值