Hadoop YARN ResourceManager高可用(HA)实战配置与故障排查

发布时间:2026/10/27 4:02:15
Hadoop YARN ResourceManager高可用(HA)实战配置与故障排查

1. 项目概述:为什么 ResourceManager 高可用不是“可选项”,而是集群生死线

你刚在某高校实验室搭好一套 Hadoop 3.3.6 集群,三台物理机跑着 YARN,跑着几个 Spark SQL 作业和一个实时日志分析任务。某天凌晨两点,ResourceManager 进程突然 OOM 崩溃——没启自动拉起,没配故障转移,整个集群的资源调度瞬间停摆。所有正在运行的 ApplicationMaster 失联,新提交的作业卡在 ACCEPTED 状态不动,Flink 任务 checkpoint 失败,Spark UI 上 Application 列表灰成一片。运维同学被电话叫醒,手动 ssh 登录、查日志、重启 RM、等 RM 重载 NM 注册、等 NodeManager 逐个心跳恢复……整整 12 分钟,业务中断。这不是虚构场景,是我在某跨平台数据中台项目里实打实踩过的坑。

Hadoop-Yarn-ResourceManagerHA,说白了就是给 YARN 的“大脑”——ResourceManager(RM)装上双脑甚至多脑冗余机制。它不解决计算慢、磁盘小、网络抖动这些“身体问题”,但直接决定集群有没有“意识”:RM 挂了,YARN 就等于植物人——ApplicationMaster 找不到调度器,Container 申请无响应,整个资源管理层彻底失能。而 HA 的核心价值,从来不是“让集群看起来更高级”,而是把单点故障导致的分钟级不可用压缩到秒级自动接管。

这个标题背后藏着三个硬核事实:第一,RM HA 不是 Hadoop 2.x 的“实验特性”,而是从 Hadoop 2.4 开始就进入生产就绪状态的成熟方案;第二,它不依赖 ZooKeeper 做“选主”就完事,而是深度耦合了状态存储、事件回放、客户端重试三大机制;第三,配置错一个参数,比如yarn.resourcemanager.store.class指向了错误的实现类,或者yarn.resourcemanager.zk-state-store.address拼错了端口,集群启动后表面正常,但 failover 时会静默失败——这种问题查起来比内存泄漏还折磨人。

适合谁看?如果你正准备上线一个日均处理 50TB+ 数据的离线数仓,或支撑着 20+ 业务方实时任务的流批一体平台,又或者只是想搞懂“为什么公司集群的 RM 总是双活却从不切换”,那这篇就是为你写的。它不讲 Hadoop 架构图,不堆概念定义,只拆解真实部署中每一步“为什么这么配”“不这么配会怎样”“日志里哪行字暴露了你的配置漏洞”。接下来,我们就从设计逻辑开始,一层层剥开 RM HA 的真实肌理。

2. 整体架构设计与方案选型:为什么必须用 ZooKeeper + StateStore,而不是自己写心跳检测

2.1 核心矛盾:高可用 ≠ 双进程简单互备

很多人初学 RM HA,第一反应是:“我起两个 RM 进程,A 挂了就切到 B,不就完了?”——这恰恰是最大误区。YARN 的 RM 不是 Nginx 那种无状态反向代理,它内部维护着极其复杂的运行时状态:所有活跃 Application 的元信息(AppID、用户、队列、优先级)、每个 ApplicationMaster 的位置与健康状态、所有已分配 Container 的生命周期、当前各队列的资源使用水位、甚至 Scheduler 内部的排队队列结构。如果只是简单地 A 挂 B 启,B 根本不知道 A 死前最后一秒发生了什么:某个 App 刚申请了 100 个 vCore 却还没分配完,某个 Container 正在被 Kill 却没发通知……B 直接接管,轻则资源错配、任务假死,重则引发资源泄露雪崩。

所以 RM HA 的本质,是解决状态一致性问题,而非进程存活问题。这就引出了第一个关键设计选择:必须引入外部协调服务来管理“谁是 Active”以及“状态存哪”。

2.2 为什么是 ZooKeeper?不是 etcd,不是 Consul,更不是自研

Hadoop 官方文档明确支持 ZooKeeper 作为 RM HA 的协调后端,原因非常务实:

  • 强一致性保障:ZooKeeper 的 ZAB 协议保证了所有客户端看到的状态变更顺序严格一致。当 Active RM 崩溃,Standby RM 通过 ZooKeeper 的 Watch 机制感知到/yarn-leader-election节点变化,它必须先完成“状态同步”才能升级为 Active。这个“同步”过程,就是从共享的 StateStore 加载最新快照+增量日志。如果用最终一致性的 etcd(默认配置),两个 RM 可能同时认为自己是 Active,造成脑裂——一个任务被两个 RM 同时调度,资源重复分配,后果灾难性。

  • 成熟的故障检测能力:ZooKeeper 自带 session 机制。RM 进程以临时节点(ephemeral node)形式注册在/yarn-leader-election下。只要 RM 进程崩溃或网络断开超过 session timeout(默认 10 秒),ZooKeeper 自动删除该节点,无需 RM 自己发心跳包、无需额外监控脚本判断“进程是否活着”。我们实测过,在模拟网络分区场景下,ZooKeeper 平均 8.3 秒内就能触发 failover,而自研基于 TCP 心跳的方案,受 GC 暂停影响,最长出现过 47 秒的误判窗口。

  • 生态兼容性零成本:绝大多数 Hadoop 生产集群早已部署 ZooKeeper 用于 HDFS NameNode HA(ZKFC)、HBase Master 选举、Kafka Controller 选举。复用同一套 ZooKeeper 集群,省去独立运维一套协调服务的成本。我们曾对比过:为 RM HA 单独部署 3 节点 etcd,运维复杂度提升 40%,而复用现有 ZooKeeper,只需新增 2 个 ACL 权限配置。

提示:不要试图用 Redis 或 MySQL 替代 ZooKeeper。Redis 的哨兵模式无法保证强一致,MySQL 的主从延迟会导致 Standby RM 加载到过期状态。官方明确不支持,社区也从未有稳定生产案例。

2.3 StateStore:状态存哪?为什么不能只靠 ZooKeeper

ZooKeeper 本身不是数据库,它不适合存储大量、频繁更新的运行时状态(比如每秒上千次的 Container 状态变更)。它的设计目标是协调,不是持久化。因此,Hadoop 引入了StateStore抽象层,作为 RM 状态的“主存储”,而 ZooKeeper 只负责“选主”和“通知”。

Hadoop 提供两种 StateStore 实现:

  • org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore:基于 ZooKeeper 的轻量级实现,适合中小集群(< 500 节点)。它把 Application、Attempt、Reservation 等关键元数据序列化后存入 ZooKeeper 的 znode,利用 ZooKeeper 的原子性保证一致性。优点是部署极简,无需额外服务;缺点是 ZooKeeper 节点数量膨胀快,单个 znode 有 1MB 限制,超大集群易触发NoNodeException。
  • org.apache.hadoop.yarn.server.resourcemanager.recovery.FileSystemRMStateStore:基于 HDFS 的实现,适合大型集群(> 500 节点)。所有状态以序列化文件形式存入 HDFS 的指定目录(如/yarn/rmstate),利用 HDFS 的高吞吐、大容量优势。优点是扩展性好,状态存储无上限;缺点是引入了 HDFS 依赖,且需确保 HDFS 本身高可用(否则 RM HA 成为单点)。

我们在线上集群的选择逻辑很直接:如果 HDFS 已经是 HA 架构(Active/Standby NN + QJM),那就毫不犹豫选FileSystemRMStateStore。因为 HDFS 的可靠性远高于 ZooKeeper 的 znode 存储能力。我们曾在一个 1200 节点集群中测试:当 StateStore 使用 ZK 实现时,ZooKeeper 集群 CPU 在高峰期持续 92%+,而切换到 HDFS 后,ZooKeeper CPU 降至 35% 以下,且 RM failover 时间从平均 18 秒缩短至 9 秒——因为 Standby RM 加载 HDFS 上的快照文件,比从 ZooKeeper 逐个读取上千个 znode 快得多。

2.4 客户端透明性:应用代码完全不用改,靠的是这三层重试机制

RM HA 对上层应用(MapReduce、Spark、Flink)必须是“零感知”的,这是硬性要求。Hadoop 实现这一点,靠的不是魔法,而是三重精密的客户端重试策略:

  1. RM 地址解析层重试:客户端(如yarn-client)首次连接时,会从yarn.resourcemanager.hostname获取 Active RM 地址。如果连接失败(Connection refused / Timeout),它不会报错退出,而是立即调用ClientRMService.getRMHAId(),通过 ZooKeeper 查询当前 Active RM 的 ID(如rm1或rm2),再根据yarn.resourcemanager.[rm-id].address配置获取新地址重试。这个过程对用户代码完全透明。

  2. RPC 层重试:即使连接上了 Active RM,如果 RPC 调用过程中 RM 发生 failover(比如正在提交 Application 时 Active 切换),客户端会收到StandbyException。此时YarnClientImpl会捕获该异常,主动 sleep 1 秒后,重新走第一步的地址解析流程,再次发起 RPC。

  3. ApplicationMaster 主动重连:AM 启动后,会与 RM 建立长连接。如果连接断开,AM 不会自杀,而是进入RECONNECTING状态,每隔 1 秒尝试重连,直到成功。这保证了即使 RM 切换期间 AM 与旧 RM 断连,也能在新 RM 上续上任务。

这三层重试叠加,使得一次 RM failover 对上层作业的影响,通常只是 3~5 秒的短暂延迟,而非任务失败。我们在压测中故意 kill Active RM,观察 Spark Streaming 作业:最大的延迟出现在第 3 个 micro-batch,耗时增加 4.2 秒,后续 batch 全部恢复正常。

3. 核心配置与实操要点:每一行配置背后的血泪教训

3.1 配置文件清单与作用域划分

RM HA 涉及 4 个核心配置文件,必须严格区分作用域:

文件名作用域关键说明
core-site.xml所有节点(NN, DN, RM, NM)配置 ZooKeeper 集群地址fs.defaultFS和ha.zookeeper.quorum,这是全局协调基础
hdfs-site.xml所有节点配置 HDFS HA 相关参数(如dfs.ha.automatic-failover.enabled),若 StateStore 用 HDFS,则此处必须启用
yarn-site.xml仅 RM 节点最关键的配置文件,包含 RM HA 所有开关、地址、Store 类型等。NM 和客户端绝对不能在此文件中配置 RM HA 参数,否则 NM 会尝试启动 RM 服务导致端口冲突!
mapred-site.xml客户端 & MR AppMaster配置mapreduce.framework.name=yarn,确保 MapReduce 作业走 YARN 调度

注意:yarn-site.xml中的yarn.resourcemanager.ha.enabled必须设为true,且只能在真正的 RM 节点上设置。我们曾因运维脚本错误,将此配置推送到所有 NM 节点,导致 NM 进程启动时尝试绑定 8030/8031 端口,与 RM 冲突,整个集群 NM 全部启动失败。排查了 6 小时才发现是配置污染。

3.2yarn-site.xml核心参数详解(附真实值与原理)

以下是我们线上集群(Hadoop 3.3.6,1200 节点)的yarn-site.xml关键片段,每行都标注了“为什么这么配”:

<!-- 【开关】必须开启 HA --> <property> <name>yarn.resourcemanager.ha.enabled</name> <value>true</value> </property> <!-- 【ID 列表】定义集群中所有 RM 实例的唯一标识 --> <property> <name>yarn.resourcemanager.ha.rm-ids</name> <value>rm1,rm2,rm3</value> <!-- 三个 RM,实现 N+1 冗余 --> </property> <!-- 【主机名映射】每个 RM ID 对应的物理主机 --> <property> <name>yarn.resourcemanager.hostname.rm1</name> <value>rm-node1.example.com</value> <!-- rm1 运行在 rm-node1 --> </property> <property> <name>yarn.resourcemanager.hostname.rm2</name> <value>rm-node2.example.com</value> <!-- rm2 运行在 rm-node2 --> </property> <property> <name>yarn.resourcemanager.hostname.rm3</name> <value>rm-node3.example.com</value> <!-- rm3 运行在 rm-node3 --> </property> <!-- 【RPC 地址】每个 RM 的 IPC 通信端口(必须唯一,避免冲突) --> <property> <name>yarn.resourcemanager.address.rm1</name> <value>rm-node1.example.com:8032</value> </property> <property> <name>yarn.resourcemanager.address.rm2</name> <value>rm-node2.example.com:8032</value> </property> <property> <name>yarn.resourcemanager.address.rm3</name> <value>rm-node3.example.com:8032</value> </property> <!-- 【Web UI 地址】每个 RM 的 HTTP 端口 --> <property> <name>yarn.resourcemanager.webapp.address.rm1</name> <value>rm-node1.example.com:8088</value> </property> <property> <name>yarn.resourcemanager.webapp.address.rm2</name> <value>rm-node2.example.com:8088</value> </property> <property> <name>yarn.resourcemanager.webapp.address.rm3</name> <value>rm-node3.example.com:8088</value> </property> <!-- 【ZooKeeper 协调】指向 ZooKeeper 集群地址 --> <property> <name>yarn.resourcemanager.zk-address</name> <value>zk1.example.com:2181,zk2.example.com:2181,zk3.example.com:2181</value> </property> <!-- 【StateStore 类型】选择 HDFS 存储,非 ZooKeeper --> <property> <name>yarn.resourcemanager.store.class</name> <value>org.apache.hadoop.yarn.server.resourcemanager.recovery.FileSystemRMStateStore</value> </property> <!-- 【StateStore 根路径】HDFS 上的专用目录,必须由 yarn 用户可写 --> <property> <name>yarn.resourcemanager.fs.state-store.uri</name> <value>hdfs://mycluster/yarn/rmstate</value> </property> <!-- 【ZooKeeper Session Timeout】ZooKeeper 会话超时时间,单位毫秒 --> <property> <name>yarn.resourcemanager.zk-timeout-ms</name> <value>10000</value> <!-- 10 秒,与 ZooKeeper server 的 tickTime * 2 匹配 --> </property> <!-- 【自动故障转移】必须开启,否则需要手动执行 yarn rmadmin -transitionToActive --> <property> <name>yarn.resourcemanager.ha.automatic-failover.enabled</name> <value>true</value> </property> <!-- 【自动故障转移实现类】ZooKeeper 选主实现 --> <property> <name>yarn.resourcemanager.ha.automatic-failover.zk-base-path</name> <value>/yarn-leader-election</value> <!-- ZooKeeper 中选举节点的根路径 --> </property>

关键原理补充:

  • yarn.resourcemanager.zk-timeout-ms必须与 ZooKeeper 服务端的tickTime参数匹配。ZooKeeper 默认tickTime=2000ms,session timeout 最小值为2*tickTime=4000ms,最大值为20*tickTime=40000ms。我们设为10000ms,既保证网络抖动时不误判,又确保故障能快速发现。如果设为5000ms,在 GC 暂停 6 秒的场景下,RM 会被 ZooKeeper 强制踢出,引发不必要的 failover。
  • yarn.resourcemanager.fs.state-store.uri指向的 HDFS 路径,必须提前创建并授权:hdfs dfs -mkdir -p /yarn/rmstate && hdfs dfs -chown yarn:yarn /yarn/rmstate && hdfs dfs -chmod 700 /yarn/rmstate。如果权限不对,Standby RM 启动时会报AccessControlException,日志里只有一行Failed to initialize state store,根本看不出是权限问题。

3.3 启动与验证全流程:从启动命令到日志定位

启动步骤(严格按顺序):
  1. 确保 ZooKeeper 集群健康:echo stat | nc zk1.example.com 2181 | grep Mode,输出Mode: follower或Mode: leader表示正常。

  2. 确保 HDFS HA 正常:hdfs haadmin -getServiceState nn1返回active,hdfs haadmin -getServiceState nn2返回standby。

  3. 在所有 RM 节点启动 RM 服务:

    # 在 rm-node1 上执行 $HADOOP_HOME/sbin/yarn-daemon.sh start resourcemanager # 在 rm-node2 上执行 $HADOOP_HOME/sbin/yarn-daemon.sh start resourcemanager # 在 rm-node3 上执行 $HADOOP_HOME/sbin/yarn-daemon.sh start resourcemanager

    注意:不要用start-yarn.sh,它会错误地在所有节点启动 RM,导致端口冲突。必须手动在每个 RM 节点单独启动。

  4. 验证 Active/Standby 状态:

    # 查看哪个 RM 是 Active $HADOOP_HOME/bin/yarn rmadmin -getServiceState rm1 # 输出 active 或 standby $HADOOP_HOME/bin/yarn rmadmin -getServiceState rm2 $HADOOP_HOME/bin/yarn rmadmin -getServiceState rm3

    正常情况:一个active,两个standby。

日志定位黄金法则:
  • Active RM 日志:$HADOOP_LOG_DIR/yarn-*-resourcemanager-*.log,重点搜索Transitioning to active state,确认它已成功加载 StateStore。
  • Standby RM 日志:同上,搜索Transitioning to standby state和Recovering applications and reservations,确认它已从 HDFS 加载了最新状态。
  • ZooKeeper 选举日志:在yarn-*-resourcemanager-*.log中搜索ZKRMStateStore,如果看到Successfully connected to ZooKeeper和Creating ZK root node,说明协调正常。
  • 最致命的错误日志:java.io.IOException: Failed to load application state—— 这表示 StateStore 加载失败,90% 是 HDFS 路径权限问题或 HDFS 不可用。

我们曾遇到一个诡异问题:yarn rmadmin -getServiceState rm1返回standby,但yarn rmadmin -getServiceState rm2也返回standby,三个 RM 全是 standby。查日志发现,所有 RM 都在报org.apache.zookeeper.KeeperException$ConnectionLossException。根源是 ZooKeeper 集群的maxClientCnxns参数设为 60,而三个 RM 各自建立了 20+ 连接,超限后新连接被拒绝。解决方案:在zoo.cfg中将maxClientCnxns=200,重启 ZooKeeper。

4. 实操过程与核心环节实现:手把手带你完成一次安全的 failover 演练

4.1 演练前的必备检查清单

在生产环境执行任何 failover 操作前,必须完成以下 7 项检查,缺一不可:

  1. ZooKeeper 健康检查:echo ruok | nc zk1.example.com 2181返回imok;echo mntr | nc zk1.example.com 2181 | grep zk_followers确认 follower 数量 ≥ 2。
  2. HDFS 状态检查:hdfs dfsadmin -report确认Configured Capacity和DFS Used%正常;hdfs haadmin -getServiceState nn1确认 NN HA 正常。
  3. RM 进程检查:ps aux | grep ResourceManager确认每个 RM 节点只有一个org.apache.hadoop.yarn.server.resourcemanager.ResourceManager进程。
  4. StateStore 目录检查:hdfs dfs -ls /yarn/rmstate应看到VERSION、RMStateRoot等子目录,且hdfs dfs -du -h /yarn/rmstate显示大小在合理范围(我们集群约 1.2GB,每天增长 50MB)。
  5. 客户端配置检查:yarn-site.xml中yarn.resourcemanager.ha.enabled=true,且yarn.resourcemanager.ha.rm-ids与实际节点一致。
  6. 防火墙检查:确保 RM 节点间 8030/8031/8032/8088 端口互通,且与 ZooKeeper 的 2181 端口互通。
  7. 备份检查:cp $HADOOP_CONF_DIR/yarn-site.xml{,.backup-$(date +%Y%m%d)},防止配置误操作。

提示:我们把这 7 项检查写成一个check-rm-ha.sh脚本,每次演练前自动执行,输出PASS或具体失败项。这比人工检查快 5 倍,且杜绝遗漏。

4.2 手动触发 failover 的完整步骤与预期现象

目标:将当前 Active RM(假设是rm1)强制切换到rm2,全程监控状态变化。

步骤 1:确认初始状态
# 在任意节点执行 $HADOOP_HOME/bin/yarn rmadmin -getServiceState rm1 # 应输出 "active" $HADOOP_HOME/bin/yarn rmadmin -getServiceState rm2 # 应输出 "standby" $HADOOP_HOME/bin/yarn rmadmin -getServiceState rm3 # 应输出 "standby"
步骤 2:强制将 rm1 切为 standby
# 在 rm1 节点执行(注意:必须在 rm1 本机执行) $HADOOP_HOME/bin/yarn rmadmin -transitionToStandby --forcemanual rm1

预期现象:

  • yarn rmadmin -getServiceState rm1立即返回standby。
  • rm1的yarn-*-resourcemanager-*.log中出现Transitioning to standby state。
  • rm2的日志中开始出现Recovering applications and reservations from state store,并打印加载的 Application 数量(如Recovered 127 applications)。
  • rm2的日志中出现Transitioning to active state。
  • yarn rmadmin -getServiceState rm2返回active。
步骤 3:验证服务连续性
  • 提交一个新作业:yarn jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-*.jar pi 10 1000000。
  • 观察yarn logs -applicationId application_XXXXX,确认日志能正常拉取。
  • 访问http://rm-node2.example.com:8088(新 Active RM 的 Web UI),确认 Applications 列表显示所有运行中任务,且Cluster Metrics中Active Nodes数量与实际 NM 数量一致。
步骤 4:恢复 rm1 为 standby(可选)
# 在 rm1 节点执行,让它重新加入 standby 队列 $HADOOP_HOME/bin/yarn rmadmin -transitionToStandby --forcemanual rm1

此时rm1会重新从 StateStore 加载状态,成为 standby。

关键细节:

  • --forcemanual参数是必须的,因为自动 failover 需要 ZooKeeper 协调,而手动切换绕过 ZooKeeper,强制改变状态。
  • 切换过程通常在 8~15 秒内完成,取决于 StateStore 大小。我们集群 1.2GB StateStore,平均耗时 11.3 秒。
  • 切换期间,正在运行的 Application 不会中断,AM 会自动重连新 Active RM。但新提交的作业会有 3~5 秒延迟。

4.3 自动 failover 故障注入测试:模拟真实崩溃场景

手动切换是“可控手术”,自动 failover 才是“真实战场”。我们必须验证:当 Active RM 进程真正崩溃时,Standby 是否能无缝接管。

测试方法(在 rm1 节点执行):
# 1. 获取 RM 进程 PID PID=$(ps aux | grep ResourceManager | grep -v grep | awk '{print $2}') # 2. 发送 SIGKILL 强制终止(模拟 OOM 崩溃) kill -9 $PID # 3. 立即监控日志 tail -f $HADOOP_LOG_DIR/yarn-*-resourcemanager-*.log | grep -E "(active|standby|Recovering|Transitioning)"
预期日志流(rm2 日志):
2023-10-05 14:22:31,102 INFO org.apache.hadoop.yarn.server.resourcemanager.AdminService: Transitioning to active state 2023-10-05 14:22:31,105 INFO org.apache.hadoop.yarn.server.resourcemanager.recovery.FileSystemRMStateStore: Loading applications and reservations from hdfs://mycluster/yarn/rmstate 2023-10-05 14:22:35,892 INFO org.apache.hadoop.yarn.server.resourcemanager.recovery.FileSystemRMStateStore: Recovered 127 applications 2023-10-05 14:22:36,001 INFO org.apache.hadoop.yarn.server.resourcemanager.ResourceManager: Transitioning to active state
验证指标:
  • Failover 时间:从rm1进程消失,到rm2日志打出Transitioning to active state的时间差。我们集群 SLA 要求 ≤ 15 秒,实测平均 12.7 秒。
  • Application 连续性:用yarn application -list检查,所有RUNNING状态的应用在 failover 后仍为RUNNING,无FAILED或KILLED。
  • 资源视图一致性:访问http://rm-node2.example.com:8088/cluster/nodes,确认 NodeManager 列表与故障前完全一致,无节点丢失。

实操心得:第一次做自动 failover 测试时,我们发现rm2日志卡在Loading applications...超过 2 分钟。排查发现是 HDFS 的dfs.client.failover.max.attempts默认值为 15,而我们的 HDFS NameNode 切换需要 20 秒,导致 RM 重试超时。解决方案:在yarn-site.xml中添加<property><name>dfs.client.failover.max.attempts</name><value>30</value></property>,问题解决。

5. 常见问题与排查技巧实录:那些让你半夜爬起来的日志线索

5.1 问题速查表:症状、日志关键词、根本原因、解决方案

症状日志关键词(在 RM 日志中搜索)根本原因解决方案
所有 RM 都是 standbyKeeperException$ConnectionLossException,Unable to connect to ZooKeeperZooKeeper 集群不可用或网络不通检查 ZooKeeper 进程、端口、防火墙;echo ruok | nc zk1 2181
Standby RM 无法加载状态Failed to load application state,AccessControlExceptionStateStore HDFS 路径权限不足或 HDFS 不可用hdfs dfs -chown yarn:yarn /yarn/rmstate; 检查 HDFS NN 状态
failover 后 Application 全部失败ApplicationNotFoundException,InvalidApplicationIdExceptionStateStore 中的 Application 状态损坏或版本不兼容清空/yarn/rmstate(需先停所有 RM),重启 RM;升级 Hadoop 版本保持兼容
RM 启动报端口占用Address already in use,BindException配置错误导致多个 RM 绑定同一端口,或旧进程未清理检查yarn-site.xml中yarn.resourcemanager.address.rm*是否唯一;ps aux | grep ResourceManager | xargs kill -9
Web UI 无法访问新 Active RMConnection refusedon port 8088新 Active RM 的yarn.resourcemanager.webapp.address配置错误检查yarn-site.xml中yarn.resourcemanager.webapp.address.rm2是否指向正确主机名
failover 时间过长(> 30 秒)Recovering applications...日志长时间无进展StateStore 过大或 HDFS 延迟高优化 HDFS 配置(dfs.client.read.shortcircuit);考虑迁移到ZKRMStateStore(小集群)

5.2 独家避坑技巧:来自 12 次生产事故的总结

技巧 1:ZooKeeper ACL 权限必须精确到路径
很多团队给 ZooKeeper 设置了全局world:anyone:cdrwa权限,看似方便,实则埋雷。Hadoop RM HA 会在/yarn-leader-election下创建临时节点,如果权限太宽,其他服务可能误删该节点。正确做法:

# 创建专用 ACL echo "addauth digest yarn:password" | ./zkCli.sh -server zk1:2181 setAcl /yarn-leader-election auth:yarn:password:cdrwa # 然后在 yarn-site.xml 中配置 <property> <name>yarn.resourcemanager.zk-acl</name> <value>auth:yarn:password:cdrwa</value> </property>

技巧 2:StateStore 目录必须启用 HDFS Trash
HDFS 默认开启 Trash(回收站),但 StateStore 目录是个例外。如果rmstate目录被意外删除,Trash 会保留它,Standby RM 启动时会尝试从 Trash 加载损坏的快照,导致启动失败。解决方案:在hdfs-site.xml中禁用该目录的 Trash:

<property> <name>fs.defaultFS</name> <value>hdfs://mycluster</value> </property> <property> <name>fs.trash.checkpoint.interval</name> <value>0</value> <!-- 全局禁用,或 --> </property> <!-- 更推荐:在 core-site.xml 中为 rmstate 路径单独禁用 --> <property> <name>fs.defaultFS</name> <value>hdfs://mycluster</value> </property> <property> <name>fs.trash.interval</name> <value>0</value> <description>Disable trash for rmstate</description> </property>

技巧 3:监控指标必须抓取 ZooKeeper 的zk_followers
不要只监控 RM 进程是否存在。真正的 failover 风险信号是 ZooKeeper 集群的 follower 数量下降。当zk_followers < 2时,ZooKeeper 无法达成多数派,RM 选举必然失败。我们在 Prometheus 中配置了告警规则:zookeeper_mntr{job="zookeeper"} * on(instance) group_left() (count by(instance)(zookeeper_mntr{zk_followers=~".+"}) < 2),一旦触发,立即通知 SRE 团队检查 ZooKeeper。

技巧 4:定期清理 StateStore 的旧快照
FileSystemRMStateStore会定期生成快照(snapshot),但不会自动清理。我们集群的/yarn/rmstate/RMStateRoot/.snapshot目录下积累了 200+ 个快照,占用了 80GB 空间。Hadoop 本身不提供清理工具,我们写了一个 Python 脚本,每周清理 30 天前的快照:

import subprocess import datetime # ... 获取 HDFS 快照列表,计算日期,执行 hdfs dfs -rm -r /yarn/rmstate/.snapshot/snapshot_20231001

不清理的后果: