ResourceManager因為塊丟失而重啟失敗

  • 2019 年 12 月 6 日
  • 筆記

在非HA情況下,如果HDFS中RM-Restart相關的塊丟失,會導致RM無法啟動。

RM重啟失敗日誌:

錯誤日誌

查看查看HDFS丟失塊:

該出的塊丟失之所以能影響RM的啟動,是因為集群默認開啟了ResourceManager Restart功能。

ResourceManager Restart

社區對RM重啟功能的完善分為兩個階段:

1. 第一階段(Non-work-preserving RM restart)

     當客戶端提交application時,RM會將App的元數據資訊(ApplicationSubmissionContext)保存在HDFS中(非HA)或者ZooKeeper(HA集群),同時也會在應用結束時保存應用的最終狀態比如完成態(failed, killed, finished)和診斷資訊。此外,RM還可以將security keys, tokens保存起來。

    RM重新啟動時,它可以從HDFS或者ZooKooper讀取這些App的狀態資訊。RM會對完成狀態的APP(failed, killed, finished)和仍在運行中的APP對區分處理:

(1)對於完成態的App,RM僅僅是將保存的資訊重新載入到記憶體中。這麼做的典型場景就是在RM重啟後,yarn的WEB UI仍然能看到歷史的記錄任務。

(2)對於運行中的App,RM會將該kill掉APP的ApplicationMaster和container,重新提交該App任務。RM掉線時,NodeManager會一直輪詢RM,直到該進程上線。RM復活後會給所有仍在運行的ApplicationMaster,NodeManager發送re-sync命令, 接收到該命令後container和AM會被kill掉,而RM會將會根據保存的App資訊,將該App重新啟動。

階段1是在Hadoop2.4.0實現,該階段的主要問題是:一旦RM重啟,所有正在運行中的任務將重新開始跑,對於耗時久的任務來說,這種行為是不可接受的。

2. 第二階段(Work-preserving RM restart)

    階段2是在Hadoop2.6.0才開始實現的。主要功能就是在階段1的基礎上增加:RM重啟後仍保證運行狀態的App繼續執行,App可以簡單地重新與RM同步,並從停止的地方恢復。

    當NM與重新啟動的RM進行同步時,NM不會kill掉container ,而且會將container的狀態發送給RM。 RM通過這些container的資訊來重建container和對應App的調度狀態。與此同時,AM需要將未完成的資源請求重新發送給RM,因為RM在關閉時可能會丟失這些未完成的請求。

ResourceManager Restart Configurations

開啟RM重啟功能,默認值false:

<property>      <description>Enable RM to recover state after starting. If true, then        yarn.resourcemanager.store.class must be specified. </description>      <name>yarn.resourcemanager.recovery.enabled</name>      <value>false</value>  </property>

 配置state-store:

<property>      <name>yarn.resourcemanager.store.class</name>      <value>org.apache.hadoop.yarn.server.resourcemanager.recovery.FileSystemRMStateStore</value>  </property>

 該參數屬性主要使用兩類:

(1)org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore,HA集群配置該存儲類。

(2)org.apache.hadoop.yarn.server.resourcemanager.recovery.FileSystemRMStateStore,非HA集群配置,將狀態資訊存儲在HDFS。

其他參數可參考官網。

回歸到文章開頭的問題,在非HA集群中,RM會將App的狀態資訊存儲在${hadoop.tmp.dir}/yarn/system/rmstore路徑下,在EMR中該路徑就是/data/emr/hdfs/tmp/yarn/system/rmstore/。由於該路徑下的/data/emr/hdfs/tmp/yarn/system/rmstore/FSRMStateRoot/EpochNode的塊丟失,導致了重啟失敗。

如下程式碼,重啟時要從這些路徑去讀取App狀態。

 protected void serviceStart() throws Exception {        RMStateStore rmStore = rmContext.getStateStore();        // The state store needs to start irrespective of recoveryEnabled as apps        // need events to move to further states.        rmStore.start();          if(recoveryEnabled) {          try {            LOG.info("Recovery started");            rmStore.checkVersion();            if (rmContext.isWorkPreservingRecoveryEnabled()) {  讀取 /data/emr/hdfs/tmp/yarn/system/rmstore/FSRMStateRoot/EpochNode              rmContext.setEpoch(rmStore.getAndIncrementEpoch());            }  讀取/data/emr/hdfs/tmp/yarn/system/rmstore/FSRMStateRoot/RMAppRoot            RMState state = rmStore.loadState();            recover(state);            LOG.info("Recovery ended");          } catch (Exception e) {            // the Exception from loadState() needs to be handled for            // HA and we need to give up master status if we got fenced            LOG.error("Failed to load/recover state", e);            throw e;          }        }          super.serviceStart();      }

解決方案:

刪除這些壞塊,RM就能重新啟動。HDFS中產生丟失塊的大部分原因是沒有使用HDFS的命令刪除文件,因此為了避免丟失塊請使用HDFS的刪除命令。