讲讲YARN ResourceManager 的 HA(高可用)实现原理和架构
YARN ResourceManager (RM) 作为 Hadoop 集群的资源管理和任务调度的“大脑”,在早期版本中是单点故障(SPOF)。从 Hadoop 2.4 版本开始,YARN 引入了 ResourceManager HA(高可用)机制。
YARN RM HA 的核心思想是通过 Active/Standby(主备)模式 运行多个 ResourceManager,并借助 ZooKeeper 进行领导者选举和状态同步。
以下是 YARN ResourceManager HA 的架构和实现原理的深度解析:
一、 YARN RM HA 架构图解
在一个典型的 RM HA 架构中,主要包含以下几个核心组件:
- ResourceManager (Active):当前负责处理客户端请求、接收 NodeManager 汇报、进行资源分配和调度的 RM。
- ResourceManager (Standby):备用 RM,处于休眠状态。它不处理任何实际业务,只是时刻准备着在 Active RM 挂掉时接管工作。
- ZooKeeper 集群:负责分布式锁的提供(Leader Election)以及状态存储(RMStateStore)。
- Embedded ZKFC (ZooKeeper Failover Controller):内嵌在 RM 进程中的故障转移控制器,负责与 ZK 交互,监控 RM 健康状态并参与选举。(注:与 HDFS NameNode HA 独立的 ZKFC 进程不同,YARN 的 ZKFC 作为一个线程运行在 RM 内部)。
- RMStateStore (状态存储):用于持久化存储当前 RM 的核心元数据和应用程序状态,通常使用 ZooKeeper 充当。
二、 核心实现原理
YARN RM HA 的实现依赖于以下五个核心机制:
1. 状态持久化与恢复机制 (RMStateStore)
如果 Active RM 宕机,Standby RM 接管后需要知道集群中正在运行什么任务。因此,Active RM 会将关键状态不断写入外部存储(RMStateStore)。
- 存储哪些数据:应用程的提交信息(Application ID、提交者等)、应用程序的运行状态(AppAttempt)、安全秘钥(Delegation Tokens)等。
- 不存储哪些数据:不存储各个节点的资源使用情况(Container 状态)。因为当 Standby RM 切换为 Active 后,各个 NodeManager 会重新向新的 Active RM 发送心跳,新的 RM 会通过这些心跳动态重建集群资源视图。这种设计大大减轻了持久化存储的压力。
- 存储介质:生产环境中强烈推荐使用
ZKRMStateStore(基于 ZooKeeper)。
2. 自动领导者选举 (Leader Election)
YARN 利用 ZooKeeper 的临时节点(Ephemeral Node)机制来实现选举:
- 两个 RM 启动时,其内部的
ActiveStandbyElector(ZKFC 线程)都会尝试在 ZK 上创建一个名为ActiveStandbyElectorLock的临时节点。 - ZooKeeper 保证只有一个 RM 能创建成功。创建成功的 RM 成为 Active,创建失败的 RM 成为 Standby。
- Standby RM 会在 ZK 上对该临时节点注册一个 Watcher(监听器)。
3. 故障自动转移 (Automatic Failover)
- 当 Active RM 发生故障(如进程崩溃、机器断电)时,它与 ZK 的会话(Session)会超时断开。
- ZK 自动删除
ActiveStandbyElectorLock临时节点。 - Standby RM 的 Watcher 收到节点被删除的通知,立即尝试去创建该节点。
- 创建成功后,Standby RM 将自身状态切换为 Active。
4. 脑裂防护机制 (Fencing 隔离)
“脑裂”(Split-Brain)是指两个 RM 同时认为自己是 Active,导致集群状态混乱。YARN 采用了非常巧妙的隔离机制:
- HDFS 的做法:HDFS NameNode HA 通常使用 SSH 登录过去杀进程(Kill)的方式进行 Fencing。
- YARN 的做法:YARN 依赖 ZooKeeper 的 ACL(访问控制列表) 来实现。
- 只有当前的 Active RM 拥有修改 ZK 中
RMStateStore目录的权限。 - 如果发生了假死(例如旧的 Active RM 因为 JVM GC 暂停了很久,导致 ZK 认为它死了并把主节点交给了新 RM)。
- 当旧的 Active RM 醒来,尝试向
RMStateStore写入状态时,因为 ZK 的 ACL 权限已经在这个过程中被新 RM 抢占并重置,旧 RM 会收到一个KeeperException.NoAuth异常。 - 旧 RM 捕获到该异常后,会意识到自己已经不是合法的 Active 了,会主动将自己降级为 Standby 或者直接退出进程,从而完美避免脑裂。
- 只有当前的 Active RM 拥有修改 ZK 中
5. 客户端与 NodeManager 的透明重定向
- 客户端 (Client) 和 AppMaster:在配置文件
yarn-site.xml中,会同时配置 RM1 和 RM2 的地址。当客户端发起请求时,它会轮询(Round-Robin)列表中的 RM。如果连上的 RM 是 Standby,它会抛出StandbyException,客户端捕获后会自动重试另一个 RM,直到找到 Active 为止。 - NodeManager:同样配置了所有 RM 的地址。如果发现 Active RM 连接不上,会自动去连接另一个 RM 进行汇报。
三、 完整的故障切换流程 (Failover Workflow)
假设 RM1 是 Active,RM2 是 Standby。
- 正常运行:RM1 处理客户端请求,接收 NM 心跳,并将 Application 状态同步写入 ZK 的
RMStateStore。RM2 处于休眠等待状态。 - 灾难发生:RM1 所在的机器突然宕机。
- 锁释放:RM1 与 ZooKeeper 的 TCP 连接断开,Session 超时,ZK 上的临时锁节点被删除。
- 备机感知:RM2 内嵌的 ZKFC 监听到锁节点被删除的事件。
- 备机夺权:RM2 发起选举,成功在 ZK 上创建临时锁节点。
- 状态恢复 (Recovery):
- RM2 成为新的 Active。
- RM2 从
ZKRMStateStore读取之前 RM1 存下的 Application 状态和安全凭证。 - RM2 恢复这些 Application 的运行(比如重新拉起处于中间状态的 ApplicationMaster)。
- 资源重建:各个 NodeManager 发现 RM1 失联,轮询尝试连接 RM2。连接成功后,NM 把自己节点上的 Container 运行情况上报给 RM2,RM2 在内存中重建整个集群的资源分布图。
- 服务恢复:客户端重试连接到 RM2,集群业务无缝继续运行,用户几乎感知不到中断。
四、 总结
YARN ResourceManager HA 的设计十分轻量且优雅:
- 内嵌 ZKFC 减少了额外的进程管理负担。
- 分离状态存储与资源视图(只持久化应用状态,资源视图靠 NM 心跳重建),大大降低了高可用状态切换时的 I/O 开销,使得切换速度极快。
- 基于 ZK ACL 的 Fencing 机制,比传统的脚本 kill 方式更安全、更可靠。