请注意本文部分内容经过AI辅助生成,虽然经过笔者检查但是并不保证内容的正确性,请自行判断准确性,本文对相关后果不承担责任
本次测试基于 EMR 7.12.0 HA 集群实际配置,在创建集群时配置如下external metastore并开启HA
json
[
{
"Classification": "hive-site",
"Properties": {
"javax.jdo.option.ConnectionURL": "jdbc:mysql://172.31.14.46:3306/hive_metastore?createDatabaseIfNotExist=true",
"javax.jdo.option.ConnectionDriverName": "org.mariadb.jdbc.Driver",
"javax.jdo.option.ConnectionUserName": "hive",
"javax.jdo.option.ConnectionPassword": "hive"
}
}
]
EMR HA 集群通过部署 3 个 Master 节点,为 HDFS、YARN、HBase、Hive 等核心组件提供高可用能力。当任一 Master 节点故障时,服务可自动切换到其他节点,避免单点故障导致集群不可用。
节点拓扑
| 角色 | 实例类型 | 数量 |
|---|---|---|
| Master | m5.xlarge | 3 |
| Core | m5.xlarge | 2 |
| Task | c5.xlarge | 1 |
3 个 Master 节点信息:
| 节点 | 私有 IP | 私有 DNS |
|---|---|---|
| Master 1 | 192.168.31.118 | ip-192-168-31-118.cn-north-1.compute.internal |
| Master 2 | 192.168.18.219 | ip-192-168-18-219.cn-north-1.compute.internal |
| Master 3 | 192.168.17.6 | ip-192-168-17-6.cn-north-1.compute.internal |
HA 组件角色分布
各组件的 Active 角色分散在不同节点上,避免单节点承载所有 Active 服务:
| 组件 | Active 节点 | Standby/Backup 节点 |
|---|---|---|
| HDFS NameNode | 192.168.31.118 (nn1) | 192.168.18.219 (nn2), 192.168.17.6 (nn3) |
| YARN ResourceManager | 192.168.18.219 (rm2) | 192.168.31.118 (rm1), 192.168.17.6 (rm3) |
| HBase Master | 192.168.31.118 | 192.168.18.219, 192.168.17.6 |
| ZooKeeper | 192.168.18.219 (leader) | 192.168.31.118 (follower), 192.168.17.6 (follower) |
| Hive Metastore | 3 节点均运行(Active-Active) | --- |
| HiveServer2 | 3 节点均运行(Active-Active) | --- |
HA 架构总览
组件依赖关系
┌─────────────────────────┐
│ ZooKeeper (3节点集群) │
│ HA 架构的选举基础 │
└──────┬──────┬──────┬─────┘
│ │ │
┌──────────┘ │ └──────────┐
▼ ▼ ▼
┌───────────┐ ┌─────────────┐ ┌─────────────┐
│ ZKFC │ │ YARN RM │ │ HBase Master│
│ NN 选举 │ │ 内嵌选举 │ │ ZK 选举 │
└─────┬─────┘ └─────────────┘ └─────────────┘
▼
┌───────────┐
│ NameNode │
│ HA 切换 │
└─────┬─────┘
│
┌─────▼─────┐
│JournalNode│
│ EditLog │
│ 同步(3节点) │
└───────────┘
External MySQL (172.31.14.46:3306)
└── Hive Metastore 元数据存储(3 个 Metastore 实例共享)
各组件 HA 模式对比
| 组件 | HA 模式 | 选举/协调方式 | 故障转移 |
|---|---|---|---|
| HDFS NameNode | Active-Standby (1+2) | ZKFC + ZooKeeper | 自动 |
| YARN ResourceManager | Active-Standby (1+2) | 内嵌 ZooKeeper 选举 | 自动 |
| HBase Master | Active-Backup (1+2) | ZooKeeper | 自动 |
| ZooKeeper | Leader-Follower (1+2) | ZAB 协议内部选举 | 自动 |
| Hive Metastore | Active-Active (3) | 无需选举,多实例并行 | 客户端重连 |
| HiveServer2 | Active-Active (3) | 无需选举,多实例并行 | 客户端重连 |
HDFS NameNode HA
HDFS NameNode HA 是整个 HA 架构中最复杂的部分,涉及 ZKFC、JournalNode、Fencing 等多个机制协同工作。
配置详情
/etc/hadoop/conf/hdfs-site.xml 关键配置:
xml
<!-- 逻辑名称 -->
<property>
<name>dfs.nameservices</name>
<value>ha-nn-uri</value>
</property>
<!-- 3 个 NameNode -->
<property>
<name>dfs.ha.namenodes.ha-nn-uri</name>
<value>nn1,nn2,nn3</value>
</property>
<!-- 各 NameNode RPC 地址 -->
<property>
<name>dfs.namenode.rpc-address.ha-nn-uri.nn1</name>
<value>ip-192-168-31-118.cn-north-1.compute.internal:8020</value>
</property>
<property>
<name>dfs.namenode.rpc-address.ha-nn-uri.nn2</name>
<value>ip-192-168-18-219.cn-north-1.compute.internal:8020</value>
</property>
<property>
<name>dfs.namenode.rpc-address.ha-nn-uri.nn3</name>
<value>ip-192-168-17-6.cn-north-1.compute.internal:8020</value>
</property>
<!-- 客户端自动故障转移 -->
<property>
<name>dfs.client.failover.proxy.provider.ha-nn-uri</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>
客户端使用逻辑名称 hdfs://ha-nn-uri/ 访问 HDFS,通过 ConfiguredFailoverProxyProvider 自动发现并连接 Active NameNode,无需关心具体哪个节点是 Active。
ZKFC(ZooKeeper Failover Controller)
ZKFC 是 Hadoop 原生组件,属于 hadoop-hdfs 模块(org.apache.hadoop.hdfs.tools.DFSZKFailoverController),在 Hadoop 2.0 引入 HDFS HA 时一起加入。每个 NameNode 旁边运行一个 ZKFC 进程,负责三件事:
- 健康监控 --- 通过
HealthMonitor线程定期调用 NameNode 的monitorHealth()RPC,判断 NameNode 是否正常 - ZooKeeper 会话管理 --- 在 ZooKeeper 中维护临时节点(ephemeral znode
ActiveStandbyElectorLock),持有锁的 ZKFC 对应的 NameNode 为 Active - 触发故障转移 --- 检测到 Active NameNode 不健康时,触发自动切换
注意:只有 HDFS NameNode 使用 ZKFC。YARN ResourceManager 的故障转移是内嵌在 RM 进程里的(automatic-failover.embedded=true),不需要额外的 ZKFC 进程。
JournalNode
JournalNode 负责在 Active 和 Standby NameNode 之间同步 EditLog(编辑日志)。3 个 Master 节点各运行一个 JournalNode。
HDFS 元数据由两部分组成:
- FsImage --- 某个时间点的完整命名空间快照
- EditLog --- 快照之后的所有变更操作(创建文件、删除目录、修改权限等)
工作方式:
客户端写操作 → Active NameNode
↓ 并行写 EditLog
JournalNode 集群 (3节点,Quorum 多数派写入,2/3 成功即可)
↑ 持续读 EditLog
Standby NameNode (回放到内存,保持状态同步)
为什么不让 Active 直接把 EditLog 发给 Standby?因为如果 Active 挂了,正在传输的 EditLog 可能丢失。JournalNode 作为独立的第三方存储,即使 Active 挂了,已写入的 EditLog 不会丢。Quorum 机制保证即使一个 JournalNode 挂了,数据仍然完整。
JournalNode 没有主从之分,所有节点完全对等:
| 对比 | ZooKeeper | JournalNode |
|---|---|---|
| 角色 | Leader / Follower(有主从) | 全对等,无主从 |
| 写入方式 | 写请求必须经过 Leader 转发 | 各节点独立接受写入 |
| 节点间通信 | Leader 同步到 Follower | 节点之间不互相通信 |
| 一致性保证 | Leader 负责排序 | NameNode 侧 Quorum 写入 + epoch number |
| 节点故障 | 需要重新选举 Leader | 无需选举,多数派存活即可 |
故障转移完整流程
当 Active NameNode 发生故障时,自动切换流程如下:
1. 旧 Active NN 故障
↓
2. 旧 ZKFC 检测到 monitorHealth() 失败
↓
3. 释放 ZK 锁(或 ZKFC 也挂了则 session 超时自动释放 ephemeral znode)
↓
4. Standby ZKFC 竞争创建 /hadoop-ha/ha-nn-uri/ActiveStandbyElectorLock
(ZooKeeper 保证只有一个 ZKFC 创建成功,赢得选举)
↓
5. Fencing 隔离旧 Active(sshfence kill 旧 NN 进程,防止脑裂)
(如果 fencing 失败,不会继续提升,宁可无 Active 也不允许双 Active)
↓
6. 调用 transitionToActive() RPC 提升 Standby 为新 Active
↓
7. 新 Active 从 JournalNode 同步完所有未回放的 EditLog
↓
8. 开始接受客户端读写请求,写新的 EditLog 到 JournalNode
其中 Fencing 是关键步骤,保证任何时刻最多只有一个 Active NameNode,避免脑裂(split-brain)导致数据不一致。
YARN ResourceManager HA
配置详情
/etc/hadoop/conf/yarn-site.xml 关键配置:
xml
<property>
<name>yarn.resourcemanager.ha.enabled</name>
<value>true</value>
</property>
<property>
<name>yarn.resourcemanager.cluster-id</name>
<value>ha-rm-uri</value>
</property>
<property>
<name>yarn.resourcemanager.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
<property>
<name>yarn.resourcemanager.ha.automatic-failover.embedded</name>
<value>true</value>
</property>
<property>
<name>yarn.resourcemanager.ha.rm-ids</name>
<value>rm1,rm2,rm3</value>
</property>
<property>
<name>yarn.resourcemanager.hostname.rm1</name>
<value>ip-192-168-31-118.cn-north-1.compute.internal</value>
</property>
<property>
<name>yarn.resourcemanager.hostname.rm2</name>
<value>ip-192-168-18-219.cn-north-1.compute.internal</value>
</property>
<property>
<name>yarn.resourcemanager.hostname.rm3</name>
<value>ip-192-168-17-6.cn-north-1.compute.internal</value>
</property>
HA 机制
- 3 个 ResourceManager:1 Active + 2 Standby
- 故障转移内嵌在 RM 进程中(
automatic-failover.embedded=true),基于 ZooKeeper 选举,不需要像 NameNode 那样额外运行 ZKFC 进程 - 使用
ha-rm-uri作为集群逻辑名称
内嵌选举(Embedded Failover)
YARN RM 的故障转移选举逻辑直接写在 RM 进程代码里(automatic-failover.embedded=true),不需要像 HDFS NameNode 那样额外启动独立的 ZKFC 进程:
HDFS NameNode --- 外部选举(两个独立进程):
NameNode 进程(只管 HDFS 服务)
+
ZKFC 进程(独立进程,负责健康检查 + ZK 选举 + 故障转移)
YARN ResourceManager --- 内嵌选举(单进程):
ResourceManager 进程(YARN 服务 + 健康检查 + ZK 选举 + 故障转移,全在一个进程里)
RM 启动时自己去 ZooKeeper 抢锁,抢到就是 Active,没抢到就是 Standby。Active RM 挂了,ZK session 超时,其他 Standby RM 自动竞争成为新 Active。
设计不同是历史原因,HDFS NameNode HA 先实现,选择了外部 ZKFC 保持 NameNode 代码简洁;后来 YARN RM HA 实现时,把选举逻辑直接嵌入 RM 进程内部。功能上没有区别,都是通过 ZooKeeper 做选举,只是代码放的位置不同。
ZooKeeper 集群
3 个 Master 节点各运行一个 ZooKeeper 实例,组成 3 节点集群:
| 节点 | 角色 |
|---|---|
| 192.168.31.118 | follower |
| 192.168.18.219 | leader |
| 192.168.17.6 | follower |
Leader-Follower 模式
ZooKeeper 采用 Leader-Follower 模式,不是传统的主从复制:
- Leader --- 处理所有写请求,负责将写操作广播给 Follower 并确保多数派确认后才提交
- Follower --- 可以直接处理读请求;收到写请求时转发给 Leader
Follower 不是被动复制的"从"节点,它们主动参与写入投票,也能独立处理读请求。只是写操作的协调权集中在 Leader 上。
与 HDFS NameNode Active-Standby 的区别:
| 对比 | HDFS NameNode | ZooKeeper |
|---|---|---|
| 模式 | Active-Standby | Leader-Follower |
| Standby/Follower 能否服务 | 不能,Standby 不接受客户端请求 | 能,Follower 可以处理读请求 |
| 写入 | 只有 Active 写 | 写请求都经过 Leader,但 Follower 参与确认 |
| 选举 | 由外部 ZKFC 触发 | Leader 故障时 Follower 通过 ZAB 协议自动选举 |
在 HA 架构中的角色
ZooKeeper 是整个 HA 架构的选举基础,负责:
- HDFS NameNode 的 Active 选举(通过 ZKFC)
- YARN ResourceManager 的 Active 选举(内嵌)
- HBase Master 的 Active 选举
- HBase RegionServer 的注册和监控
3 节点集群容忍 1 个节点故障(多数派 = 2)。Leader 挂了,剩余 Follower 通过 ZAB(ZooKeeper Atomic Broadcast)协议自动选出新 Leader,不需要外部组件介入。
HBase HA
配置详情
/etc/hbase/conf/hbase-site.xml 关键配置:
xml
<property>
<name>hbase.zookeeper.quorum</name>
<value>ip-192-168-31-118...,ip-192-168-18-219...,ip-192-168-17-6...</value>
</property>
<property>
<name>hbase.rootdir</name>
<value>hdfs://ha-nn-uri/user/hbase</value>
</property>
HA 机制
- 1 Active Master + 2 Backup Masters,通过 ZooKeeper 选举
- Active Master 负责 Region 分配和负载均衡
hbase.rootdir使用 HDFS HA 逻辑名称ha-nn-uri,不绑定单个 NameNode- 集群状态:
1 active master, 2 backup masters, 2 servers, 0 dead, 1.0000 average load
Hive HA
Hive 的 HA 模式与其他组件不同,采用多实例并行运行:
| 服务 | 192.168.31.118 | 192.168.18.219 | 192.168.17.6 |
|---|---|---|---|
| hive-hcatalog-server (Metastore) | ✅ running | ✅ running | ✅ running |
| hive-server2 (HiveServer2) | ✅ running | ✅ running | ✅ running |
- 3 个 Metastore 实例都可以接受请求,共享同一个外部 MySQL 数据库
- 3 个 HiveServer2 实例都可以接受客户端连接
- 不需要选举,任一实例故障时客户端重连到其他实例即可
与非 HA 集群的对比
| 对比项 | 非 HA 集群 | HA 集群 |
|---|---|---|
| Master 节点数 | 1 | 3 |
| HDFS NameNode | 单点 | 1 Active + 2 Standby,自动故障转移 |
| YARN ResourceManager | 单点 | 1 Active + 2 Standby,自动故障转移 |
| HBase Master | 单点 | 1 Active + 2 Backup |
| ZooKeeper | 单节点 | 3 节点集群 |
| Hive Metastore | 单实例 | 3 实例 Active-Active |
| HiveServer2 | 单实例 | 3 实例 Active-Active |
| JournalNode | 无 | 3 节点(EditLog 同步) |
| ZKFC | 无 | 3 节点(NameNode 故障转移控制) |
| 终止保护 | 默认关闭 | 默认开启 |
| Master 放置策略 | 无 | SPREAD(分散到不同硬件) |
HA 状态检查命令
bash
# HDFS NameNode 状态
sudo -u hdfs hdfs haadmin -getAllServiceState
# YARN ResourceManager 状态
yarn rmadmin -getAllServiceState
# ZooKeeper 角色
echo srvr | nc localhost 2181 | grep Mode
# HBase Master 状态
echo "status" | sudo -u hbase hbase shell
# ZKFC 服务状态
sudo systemctl status hadoop-hdfs-zkfc
# JournalNode 服务状态
sudo systemctl status hadoop-hdfs-journalnode
# Hive Metastore 服务状态
sudo systemctl status hive-hcatalog-server
# HiveServer2 服务状态
sudo systemctl status hive-server2