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