Hadoop HDFS NameNode 高可用性 (HA) 中的自动故障转移 (Automatic Failover) 核心依赖于 ZooKeeper (ZK) 和 ZKFailoverController (ZKFC) 进程的协同工作。其底层实现原理可以分解为以下几个关键部分:
-
核心组件及其角色:
- ZooKeeper (ZK): 扮演协调服务和真理之源的角色。它负责:
- 选举领导者: 通过其 Zab 协议在多个参与者中选出一个领导者。
- 维护状态信息: 存储关键的 HA 状态信息(如哪个 NN 当前是 Active)。
- 提供通知机制: 当存储的状态发生变化时,通知注册的客户端(如 ZKFC)。
- 会话管理: 跟踪客户端会话。如果客户端会话过期(通常意味着客户端崩溃或网络隔离),ZK 会删除该会话关联的所有临时节点。
- ZKFailoverController (ZKFC): 这是一个独立的轻量级进程,运行在每个 NameNode 主机上。它是实现自动故障转移的核心“大脑”,扮演两个关键角色:
- NameNode 健康监控器: 定期(通过
health-check脚本或直接 RPC)检查其本地 NameNode 的健康状态(是否响应、是否处于健康状态)。 - ZooKeeper 客户端: 与 ZooKeeper 集群交互,执行选举并响应 ZK 事件。
- NameNode 健康监控器: 定期(通过
- NameNode (NN): Active NN 处理所有客户端请求和 DataNode 心跳。Standby NN 保持状态同步(通过 QJM 或 NFS)并准备接管。
- JournalNodes (QJM): 在基于 Quorum Journal Manager 的 HA 设置中,JNs 存储 EditLog,Active NN 写入,Standby NN 读取以保持同步。故障转移后,新的 Active NN 需要确保它能获取 JNs 的独占写入权(通常通过 epoch number 实现)。
- DataNode (DN): 同时向 Active 和 Standby NN 发送心跳和块报告。
- ZooKeeper (ZK): 扮演协调服务和真理之源的角色。它负责:
-
自动故障转移的关键流程:
- 初始 Active 选举:
- 集群启动时,两个(或多个配置了 HA 的)NN 启动,各自的 ZKFC 也启动。
- 每个 ZKFC 尝试在 ZooKeeper 的一个特定临时有序节点下创建子节点(例如
/hadoop-ha/<nameservice>/ActiveStandbyElectorLock)。 - ZooKeeper 保证只有一个客户端能成功创建最小的序号节点。创建成功的 ZKFC 对应的 NameNode 成为 Active。
- 其他 ZKFC 在该节点上设置 Watch 以监听其变化。
- 健康监控与状态报告:
- 每个 ZKFC 持续地监控其本地 NameNode 的健康状态。
- 持有 Active 锁的 ZKFC 会定期向 ZK 写入一个 sessionid + 时间戳到另一个状态节点(如
/hadoop-ha/<nameservice>/ActiveBreadCrumb),这相当于一个“心跳”,表明 Active NN 是健康的且其 ZKFC 会话有效。 - 如果本地 NN 健康检查失败(无响应、状态不健康),ZKFC 会标记该 NN 为不健康。
- 故障检测:
- 本地 NN 故障: 如果 ZKFC 检测到其本地 NN 不健康(例如,进程崩溃、僵死、健康检查失败),它会决定需要触发故障转移。
- ZKFC 故障或网络隔离:
- 每个 ZKFC 与 ZK 维持一个会话。
- 如果 ZKFC 进程崩溃或其主机网络与 ZK 集群隔离,ZK 服务器检测到该 ZKFC 的会话过期。
- ZK 自动删除该会话拥有的所有临时节点,包括最重要的 Active 锁节点。
- 删除 Active 锁节点的事件会被其他正在 Watch 该节点的 ZKFC 捕获。
- 触发故障转移:
- 场景一 (由不健康 NN 的 ZKFC 主动触发): 当 ZKFC 检测到其本地 Active NN 不健康时:
- 它首先尝试优雅地将本地 NN 转为 Standby(如果可能)。
- 然后,它主动释放在 ZooKeeper 中的 Active 锁(删除其创建的临时节点)。
- 锁的删除事件被其他 ZKFC(主要是 Standby NN 的 ZKFC)捕获。
- 场景二 (由 ZK 会话过期被动触发): 当 ZK 因会话过期删除 Active 锁节点时,所有 Watch 该节点的 ZKFC(特别是 Standby NN 的 ZKFC)会收到通知。
- 场景一 (由不健康 NN 的 ZKFC 主动触发): 当 ZKFC 检测到其本地 Active NN 不健康时:
- 新 Active 选举:
- 一旦 Active 锁节点被删除(无论是主动释放还是会话过期),所有 ZKFC(包括原 Active 的 ZKFC,如果它还在运行的话)都会尝试重新创建该临时有序节点。
- ZooKeeper 再次选举:创建最小序号节点成功的 ZKFC 赢得选举。
- 故障转移执行:
- 赢得选举的 ZKFC(通常是原 Standby NN 的 ZKFC):
- 执行必要的防护 (Fencing) 操作(极其关键,见下一点)。
- 向其本地 NameNode 发送 RPC 命令,将其转换为 Active 状态。
- 更新 ZooKeeper 中的状态信息(如 ActiveBreadCrumb),声明其 NN 现在是 Active。
- 新的 Active NameNode:
- 从 JournalNodes 获取最新的 EditLog(确保 epoch 更高)。
- 开始处理客户端请求和 DataNode 心跳。
- 赢得选举的 ZKFC(通常是原 Standby NN 的 ZKFC):
- 原 Active NN 恢复处理:
- 如果原 Active NN 只是暂时性故障恢复,其 ZKFC 会检测到它已恢复健康。
- 该 ZKFC 会尝试参与选举,但此时 ZooKeeper 中已有新的 Active 锁持有者。
- 该 ZKFC 会将其本地 NN 转换为 Standby 状态,并开始从 JNs 同步状态。
- 初始 Active 选举:
-
关键机制:防护 (Fencing)
- 目的: 防止“脑裂 (Split-Brain)”。即防止在故障转移过程中或之后,出现两个 NN 都认为自己是 Active 并同时写入 EditLog,导致数据损坏。
- 时机: 在赢得选举的 ZKFC 将其本地 NN 提升为 Active 之前,必须确保旧的 Active NN 已经完全停止服务或无法再写入。
- 常用方法: 由新的 Active ZKFC 执行。
- SSH Fencing: 尝试通过 SSH 登录到旧 Active NN 主机并杀死 NN 进程(需要配置免密 SSH)。
- Shell Script Fencing: 执行一个自定义脚本,该脚本通过特定方式(如调用管理接口、断电等)停止旧 Active NN。
- QJM Fencing: 最重要且可靠的内置防护。新的 Active NN 在向 JournalNodes 写入之前,会请求一个更高的 Epoch Number。JNs 会拒绝任何使用旧 epoch 的写请求。这样,即使旧的 Active NN 还在运行并尝试写日志,也会被 JNs 拒绝,从而无法造成破坏。这是最推荐的方式,因为它直接作用于共享存储层。
- 强制的步骤: 防护操作必须成功,新的 ZKFC 才会将其 NN 提升为 Active。如果配置的所有防护方法都失败,故障转移不会完成,以避免数据损坏风险。
-
总结流程 (简版):
- ZKFC 持续监控本地 NN 健康。
- 本地 Active NN 故障或其 ZKFC 与 ZK 失联。
- Active 锁在 ZK 中丢失(主动删除或会话过期)。
- 剩余健康的 ZKFCs 检测到锁丢失,触发选举。
- 赢得选举的 ZKFC 执行防护操作杀死或隔离旧 Active NN。
- 防护成功后,该 ZKFC 命令其本地 Standby NN 转为 Active。
- 新的 Active NN 使用更高的 Epoch 从 JNs 读取最新日志并开始服务。
注意事项:
- 配置: 正确配置
hdfs-site.xml中的 HA 相关参数(特别是dfs.ha.automatic-failover.enabled=true,dfs.ha.fencing.methods, ZK 地址等)至关重要。 - ZK 稳定性: ZooKeeper 集群本身的稳定性和性能对自动故障转移的可靠性影响极大。
- 防护是核心: 没有可靠防护的自动故障转移比没有故障转移更危险,因为它可能导致数据损坏。
- 监控: 需要监控 ZKFC 进程、ZK 会话状态、NN 健康状态以及防护操作日志。
NameNode HA 的自动故障转移通过 ZK 提供的分布式协调能力和 ZKFC 的本地监控与决策逻辑,结合强制的防护机制,实现了在主 NameNode 失效时快速、安全地将备用 NameNode 提升为主节点,从而保障 HDFS 服务的高可用性。

被折叠的 条评论
为什么被折叠?



