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的刪除命令。