Yarn之狀態(tài)機分析

Yarn之狀態(tài)機分析

前言

hadoop2.x.x版本的底層實現(xiàn)中作了很多優(yōu)化:用狀態(tài)機對各種對象生命周期和狀態(tài)轉(zhuǎn)移進行管理顿膨;采用事件機制避免線程同步與阻塞。主要分析下yarn中狀態(tài)機的實現(xiàn)機制

一伍伤、事件

YARN中的很多組件之間進行通信抄邀,主要借助于事件。為了可讀性像云、可維護性及可擴展性锌雀,YARN中的事件由事件名稱和事件類型組成。比如JobImpl處理的事件名稱為JobEvent迅诬,而事件類型為JobEventType.

二腋逆、狀態(tài)

YARN中的很多組件之間進行通信,主要借助于事件侈贷。為了可讀性惩歉、可維護性及可擴展性,YARN中的事件由事件名稱和事件類型組成俏蛮。比如JobImpl處理的事件名稱為JobEvent撑蚌,而事件類型為JobEventType,如下所示

public enum JobStateInternal {
  NEW,
  SETUP,
  INITED,
  RUNNING,
  COMMITTING,
  SUCCEEDED,
  FAIL_WAIT,
  FAIL_ABORT,
  FAILED,
  KILL_WAIT,
  KILL_ABORT,
  KILLED,
  ERROR,
  REBOOT
}

我們看到JobImpl的內(nèi)部狀態(tài)包括新建(NEW)、初始化(INITED)搏屑、運行中(RUNNING)锨并、提交中(COMMITTING)、成功(SUCCEEDED)睬棚、失數谥蟆(FAILED)等

三、轉(zhuǎn)化

我們已經(jīng)了解了事件與狀態(tài)的基本實現(xiàn)與概念抑党,那么事件與狀態(tài)有什么關(guān)系?一個對象當前處于狀態(tài)state0,當對象接收到事件Event后,將引發(fā)轉(zhuǎn)換動作transition,最終當前對象的狀態(tài)過渡到state1.

1)Yarn中與狀態(tài)轉(zhuǎn)化相關(guān)的類圖如下

image.png

2)SingleArcTransition

@Public
@Evolving
public interface SingleArcTransition<OPERAND, EVENT> {
  /**
   * Transition hook.
   * 
   * @param operand the entity attached to the FSM, whose internal 
   *                state may change.
   * @param event causal event
   */
  public void transition(OPERAND operand, EVENT event);

}

由于SingleArcTransition的具體實現(xiàn)類只負責接收到事件后的具體操作或行為包警,并沒有包含狀態(tài)相關(guān)的信息,所以在狀態(tài)機執(zhí)行狀態(tài)過渡時底靠,并不是直接調(diào)用SingleArcTransition具體實現(xiàn)類的transition方法害晦,而是由接口Transition定義(見代碼清單3)真正的轉(zhuǎn)態(tài)過渡(包括行為和狀態(tài)改變)。

  • Transition接口
private interface Transition<OPERAND, STATE extends Enum<STATE>,
          EVENTTYPE extends Enum<EVENTTYPE>, EVENT> {
    STATE doTransition(OPERAND operand, STATE oldState,
                       EVENT event, EVENTTYPE eventType);
  }

  • SingleInternalArc接口

SingleInternalArc作為Transition接口的實現(xiàn)類暑中,在代理SingleArcTransition的同時壹瘟,負責狀態(tài)變換

private class SingleInternalArc
                    implements Transition<OPERAND, STATE, EVENTTYPE, EVENT> {

    private STATE postState;
    private SingleArcTransition<OPERAND, EVENT> hook; // transition hook

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

    @Override
    public STATE doTransition(OPERAND operand, STATE oldState,
                              EVENT event, EVENTTYPE eventType) {
      if (hook != null) {
        hook.transition(operand, event);
      }
      return postState;
    }
  }

3)MultipleArcTransition

@Public
@Evolving
public interface MultipleArcTransition
        <OPERAND, EVENT, STATE extends Enum<STATE>> {

  /**
   * Transition hook.
   * @return the postState. Post state must be one of the 
   *                      valid post states registered in StateMachine.
   * @param operand the entity attached to the FSM, whose internal 
   *                state may change.
   * @param event causal event
   */
  public STATE transition(OPERAND operand, EVENT event);

}

由于MultipleArcTransition的具體實現(xiàn)類只負責接收到事件后的具體操作或行為,并沒有包含狀態(tài)相關(guān)的信息鳄逾,所以在狀態(tài)機執(zhí)行狀態(tài)過渡時稻轨,并不是直接調(diào)用MultipleArcTransition具體實現(xiàn)類的transition方法,而是通過代理類MultipleInternalArc雕凹。MultipleInternalArc也實現(xiàn)了Transition接口殴俱,并在代理 MultipleArcTransition 的轉(zhuǎn)換行為的同時,負責狀態(tài)變換.

  • MultipleInternalArc
private class MultipleInternalArc
              implements Transition<OPERAND, STATE, EVENTTYPE, EVENT>{

    // Fields
    private Set<STATE> validPostStates;
    private MultipleArcTransition<OPERAND, EVENT, STATE> hook;  // transition hook

    MultipleInternalArc(Set<STATE> postStates,
                   MultipleArcTransition<OPERAND, EVENT, STATE> hook) {
      this.validPostStates = postStates;
      this.hook = hook;
    }

    @Override
    public STATE doTransition(OPERAND operand, STATE oldState,
                              EVENT event, EVENTTYPE eventType)
        throws InvalidStateTransitonException {
      STATE postState = hook.transition(operand, event);

      if (!validPostStates.contains(postState)) {
        throw new InvalidStateTransitonException(oldState, eventType);
      }
      return postState;
    }
  }

4)ApplicableTransition

為了將所有狀態(tài)機中的狀態(tài)過渡與狀態(tài)建立起映射關(guān)系枚抵,YARN中提供了ApplicableTransition接口用于將SingleInternalArc和 MultipleInternalArc 添加到狀態(tài)機的拓撲表中线欲,提高在檢索狀態(tài)對應的過渡實現(xiàn)時的性能,ApplicableTransition的實現(xiàn)類為ApplicableSingleOrMultipleTransition類汽摹,其apply方法用于代理SingleInternalArc和MultipleInternalArc 李丰,將它們添加到狀態(tài)拓撲表中。

  • ApplicableTransition接口定義
private interface ApplicableTransition
             <OPERAND, STATE extends Enum<STATE>,
              EVENTTYPE extends Enum<EVENTTYPE>, EVENT> {
    void apply(StateMachineFactory<OPERAND, STATE, EVENTTYPE, EVENT> subject);
  }

  • ApplicableSingleOrMultipleTransition
static private class ApplicableSingleOrMultipleTransition
             <OPERAND, STATE extends Enum<STATE>,
              EVENTTYPE extends Enum<EVENTTYPE>, EVENT>
          implements ApplicableTransition<OPERAND, STATE, EVENTTYPE, EVENT> {
    final STATE preState;
    final EVENTTYPE eventType;
    final Transition<OPERAND, STATE, EVENTTYPE, EVENT> transition;

    ApplicableSingleOrMultipleTransition
        (STATE preState, EVENTTYPE eventType,
         Transition<OPERAND, STATE, EVENTTYPE, EVENT> transition) {
      this.preState = preState;
      this.eventType = eventType;
      this.transition = transition;
    }

    @Override
    public void apply
             (StateMachineFactory<OPERAND, STATE, EVENTTYPE, EVENT> subject) {
      Map<EVENTTYPE, Transition<OPERAND, STATE, EVENTTYPE, EVENT>> transitionMap
        = subject.stateMachineTable.get(preState);
      if (transitionMap == null) {
        // I use HashMap here because I would expect most EVENTTYPE's to not
        //  apply out of a particular state, so FSM sizes would be 
        //  quadratic if I use EnumMap's here as I do at the top level.
        transitionMap = new HashMap<EVENTTYPE,
          Transition<OPERAND, STATE, EVENTTYPE, EVENT>>();
        subject.stateMachineTable.put(preState, transitionMap);
      }
      transitionMap.put(eventType, transition);
    }
  }

可以看到ApplicableSingleOrMultipleTransition的apply方法就是為構(gòu)建狀態(tài)拓撲表

四逼泣、狀態(tài)機

YARN中狀態(tài)機的實現(xiàn)類是StateMachineFactory趴泌,它主要包含4個屬性信息:

  • transitionsListNode:就是將狀態(tài)機的一個個過渡的ApplicableTransition實現(xiàn)串聯(lián)為一個列表舟舒,每個節(jié)點包含一個ApplicableTransition實現(xiàn)及指向下一個節(jié)點的引用
private class TransitionsListNode {
    final ApplicableTransition<OPERAND, STATE, EVENTTYPE, EVENT> transition;
    final TransitionsListNode next;

    TransitionsListNode
        (ApplicableTransition<OPERAND, STATE, EVENTTYPE, EVENT> transition,
        TransitionsListNode next) {
      this.transition = transition;
      this.next = next;
    }
  }

transitionsListNode形成的過渡列表節(jié)點如下:

image.png
  • stateMachineTable:狀態(tài)拓撲表,為了提高檢索狀態(tài)對應的過渡map而冗余的數(shù)據(jù)結(jié)構(gòu),此結(jié)構(gòu)在optimized為真時踱讨,通過對transitionsListNode鏈表進行處理產(chǎn)生
image.png
  • defaultInitialState:對象創(chuàng)建時魏蔗,內(nèi)部有限狀態(tài)機的默認初始狀態(tài)砍的。比如:JobImpl的內(nèi)部狀態(tài)機默認初始狀態(tài)是JobStateInternal.NEW痹筛。

  • optimized:布爾類型,用于標記當前狀態(tài)機是否需要優(yōu)化性能廓鞠,即構(gòu)建狀態(tài)拓撲表stateMachineTable帚稠。

  • 公共構(gòu)造器

    StateMachineFactory 的公有構(gòu)造器只有一個。

    public StateMachineFactory(STATE defaultInitialState) {
      this.transitionsListNode = null;
      this.defaultInitialState = defaultInitialState;
      this.optimized = false;
      this.stateMachineTable = null;
    }
    
    
  • 私有構(gòu)造器

    StateMachineFactory 的 私有構(gòu)造器有兩個床佳,其中代碼清單11中的構(gòu)造器在addTransition方法中使用滋早。
    從其實現(xiàn)看出,此構(gòu)造器的主要作用是構(gòu)建transitionsListNode鏈表砌们。

    private StateMachineFactory
        (StateMachineFactory<OPERAND, STATE, EVENTTYPE, EVENT> that,
         ApplicableTransition<OPERAND, STATE, EVENTTYPE, EVENT> t) {
      this.defaultInitialState = that.defaultInitialState;
      this.transitionsListNode 
          = new TransitionsListNode(t, that.transitionsListNode);
      this.optimized = false;
      this.stateMachineTable = null;
    }
    
    

    下面的構(gòu)造器則用于installTopology方法

    private StateMachineFactory
       (StateMachineFactory<OPERAND, STATE, EVENTTYPE, EVENT> that,
        boolean optimized) {
     this.defaultInitialState = that.defaultInitialState;
     this.transitionsListNode = that.transitionsListNode;
     this.optimized = optimized;
     if (optimized) {
       makeStateMachineTable();
     } else {
       stateMachineTable = null;
     }
    }
    
    

    構(gòu)造器當optimized參數(shù)為true時杆麸,調(diào)用了makeStateMachineTable方法,makeStateMachineTable的實現(xiàn)如下:

    private void makeStateMachineTable() {
      Stack<ApplicableTransition<OPERAND, STATE, EVENTTYPE, EVENT>> stack =
        new Stack<ApplicableTransition<OPERAND, STATE, EVENTTYPE, EVENT>>();
    
      Map<STATE, Map<EVENTTYPE, Transition<OPERAND, STATE, EVENTTYPE, EVENT>>>
        prototype = new HashMap<STATE, Map<EVENTTYPE, Transition<OPERAND, STATE, EVENTTYPE, EVENT>>>();
    
      prototype.put(defaultInitialState, null);
    
      // I use EnumMap here because it'll be faster and denser.  I would
      //  expect most of the states to have at least one transition.
      stateMachineTable
         = new EnumMap<STATE, Map<EVENTTYPE,
                             Transition<OPERAND, STATE, EVENTTYPE, EVENT>>>(prototype);
    
      for (TransitionsListNode cursor = transitionsListNode;
           cursor != null;
           cursor = cursor.next) {
        stack.push(cursor.transition);
      }
    
      while (!stack.isEmpty()) {
        stack.pop().apply(this);
      }
    }
    
    

    1.創(chuàng)建堆棧stack浪感,用于將transitionsListNode鏈表中各個節(jié)點持有的ApplicableSingleOrMultipleTransition壓入棧中昔头;

    2.創(chuàng)建狀態(tài)拓撲表stateMachineTable,并在此拓撲表中插入一個額外的默認初始狀態(tài)defaultInitialState與null的映射影兽;

    3.迭代訪問transitionsListNode鏈表揭斧,并將各個節(jié)點持有的ApplicableSingleOrMultipleTransition壓入棧中;

    4.依次彈出棧頂?shù)腁pplicableSingleOrMultipleTransition峻堰,并應用其apply方法(已在前面小節(jié)介紹)讹开,持續(xù)不斷的構(gòu)建狀態(tài)拓撲表stateMachineTable。

五捐名、狀態(tài)機的構(gòu)建

為了簡化敘述旦万,本節(jié)以JobImpl中狀態(tài)機的構(gòu)建為例。由于JobImpl的狀態(tài)機預設(shè)的(調(diào)用addTransition方法)加入的ApplicableSingleOrMultipleTransition非常多镶蹋,我們節(jié)選其中的2個作為典型進行分析纸型。最后還會分析installTopology方法的實現(xiàn)。

protected static final
    StateMachineFactory<JobImpl, JobStateInternal, JobEventType, JobEvent> 
       stateMachineFactory
     = new StateMachineFactory<JobImpl, JobStateInternal, JobEventType, JobEvent>
              (JobStateInternal.NEW)

          // Transitions from NEW state
          .addTransition(JobStateInternal.NEW, JobStateInternal.NEW,
              JobEventType.JOB_DIAGNOSTIC_UPDATE,
              DIAGNOSTIC_UPDATE_TRANSITION)
          .addTransition(JobStateInternal.NEW, JobStateInternal.NEW,
              JobEventType.JOB_COUNTER_UPDATE, COUNTER_UPDATE_TRANSITION)
          .addTransition
              (JobStateInternal.NEW,
              EnumSet.of(JobStateInternal.INITED, JobStateInternal.NEW),
              JobEventType.JOB_INIT,
              new InitTransition())
          // 省略其它addTransition調(diào)用
          // create the topology tables
          .installTopology();

構(gòu)建JobImpl的狀態(tài)機的步驟如下:

1.調(diào)用 StateMachineFactory 構(gòu)造器創(chuàng)建一個初始的狀態(tài)機

2.調(diào)用addTransition(STATE preState, STATE postState, EVENTTYPE eventType, SingleArcTransition<OPERAND, EVENT> hook)方法添加單弧過渡梅忌。從其實現(xiàn)(見代碼清單15)可以知道addTransition方法將SingleArcTransition封裝為SingleInternalArc狰腌,然后將SingleInternalArc封裝為ApplicableSingleOrMultipleTransition,最后調(diào)用之前說的第一個私有構(gòu)造器構(gòu)建transitionsListNode鏈表

3.調(diào)用addTransition(STATE preState, Set<STATE> postStates, EVENTTYPE eventType, MultipleArcTransition<OPERAND, EVENT, STATE> hook)方法添加多弧過渡牧氮。從其實現(xiàn)(見代碼清單16)可以知道addTransition方法將MultipleArcTransition封裝為MultipleInternalArc琼腔,然后將MultipleInternalArc封裝為ApplicableSingleOrMultipleTransition,最后調(diào)用之前說的第一個私有構(gòu)造器構(gòu)建transitionsListNode鏈表踱葛;

4.最后調(diào)用installTopology方法丹莲,其實現(xiàn)見代碼清單17光坝。installTopology正是在使用之前說的第二個私有構(gòu)造器構(gòu)建狀態(tài)拓撲表stateMachineTable

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)));
}

public StateMachineFactory
           <OPERAND, STATE, EVENTTYPE, EVENT>
        addTransition(STATE preState, Set<STATE> postStates,
                      EVENTTYPE eventType,
                      MultipleArcTransition<OPERAND, EVENT, STATE> hook){
  return new StateMachineFactory<OPERAND, STATE, EVENTTYPE, EVENT>
      (this,
       new ApplicableSingleOrMultipleTransition<OPERAND, STATE, EVENTTYPE, EVENT>
         (preState, eventType, new MultipleInternalArc(postStates, hook)));
}

public StateMachineFactory
           <OPERAND, STATE, EVENTTYPE, EVENT>
        installTopology() {
  return new StateMachineFactory<OPERAND, STATE, EVENTTYPE, EVENT>(this, true);
}

Stack<ApplicableTransition<OPERAND, STATE, EVENTTYPE, EVENT>> stack =
    new Stack<ApplicableTransition<OPERAND, STATE, EVENTTYPE, EVENT>>();

  Map<STATE, Map<EVENTTYPE, Transition<OPERAND, STATE, EVENTTYPE, EVENT>>>
    prototype = new HashMap<STATE, Map<EVENTTYPE, Transition<OPERAND, STATE, EVENTTYPE, EVENT>>>();

  prototype.put(defaultInitialState, null);

  // I use EnumMap here because it'll be faster and denser.  I would
  //  expect most of the states to have at least one transition.
  stateMachineTable
     = new EnumMap<STATE, Map<EVENTTYPE,
                         Transition<OPERAND, STATE, EVENTTYPE, EVENT>>>(prototype);

  for (TransitionsListNode cursor = transitionsListNode;
       cursor != null;
       cursor = cursor.next) {
    stack.push(cursor.transition);
  }

  //最終在這里,狀態(tài)路由表都存放到一個StateMachineFactory中了
  while (!stack.isEmpty()) {
    stack.pop().apply(this);
  }

六、例子

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末甥材,一起剝皮案震驚了整個濱河市盯另,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌洲赵,老刑警劉巖鸳惯,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異叠萍,居然都是意外死亡芝发,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門苛谷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來辅鲸,“玉大人,你說我怎么就攤上這事腹殿《楞玻” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵锣尉,是天一觀的道長刻炒。 經(jīng)常有香客問我,道長悟耘,這世上最難降的妖魔是什么落蝙? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮暂幼,結(jié)果婚禮上筏勒,老公的妹妹穿的比我還像新娘。我一直安慰自己旺嬉,他們只是感情好管行,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著邪媳,像睡著了一般捐顷。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上雨效,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天迅涮,我揣著相機與錄音,去河邊找鬼徽龟。 笑死叮姑,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播传透,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼耘沼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了朱盐?” 一聲冷哼從身側(cè)響起群嗤,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎兵琳,沒想到半個月后狂秘,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡闰围,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年赃绊,在試婚紗的時候發(fā)現(xiàn)自己被綠了既峡。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片羡榴。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖运敢,靈堂內(nèi)的尸體忽然破棺而出校仑,到底是詐尸還是另有隱情,我是刑警寧澤传惠,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布迄沫,位于F島的核電站,受9級特大地震影響卦方,放射性物質(zhì)發(fā)生泄漏羊瘩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一盼砍、第九天 我趴在偏房一處隱蔽的房頂上張望尘吗。 院中可真熱鬧,春花似錦浇坐、人聲如沸睬捶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽擒贸。三九已至,卻和暖如春觉渴,著一層夾襖步出監(jiān)牢的瞬間介劫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工案淋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留座韵,地道東北人。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓哎迄,卻偏偏與公主長得像回右,于是被迫代替她去往敵國和親隆圆。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容