深入 Elasticsearch(12):Master 选举与集群状态同步
上一篇解决了副本机制和故障恢复——primary-replica 的同步模型和 failover 流程。这一篇进入谁来决定 shard 分配、节点角色——集群协调层。
cluster state 是 ES 集群的元数据核心(第 01 篇已经介绍过它的结构)。这一篇聚焦在 cluster state 的写入方——master 节点——是怎样被选举出来的,以及选举机制在 ES 7.x 经历了什么根本性变化。
本文只抓一个问题:ES 的 master 选举算法和脑裂防护机制。
选举机制的演变
ES 7.0 之前使用 Zen Discovery,一种基于 Bully 算法变体的选举机制。这套机制需要手动配置 discovery.zen.minimum_master_nodes,配置不当容易导致脑裂。
ES 7.0 起改用全新的选举机制,基于学术论文中的共识算法思想(接近 Raft 但不是完整 Raft 实现)。新机制自动管理 quorum,不再需要手动配置 minimum_master_nodes。
| 版本 | 选举机制 | 脑裂防护 |
|---|---|---|
| < 7.0 | Zen Discovery (Bully 变体) | 手动设置 minimum_master_nodes = N/2+1 |
| ≥ 7.0 | 新共识机制(类 Raft) | 自动 quorum,voting configuration |
Master 选举过程
新选举机制的核心概念:
Master-eligible nodes 是配置了 master 角色的节点。只有 master-eligible 节点可以参与选举和投票。
Voting configuration 是参与投票的节点集合。集群自动维护这个集合——当 master-eligible 节点加入或离开集群时,voting configuration 自动更新。
选举过程:
1 | |
整个选举到状态发布的流程可以拆成四个阶段:
sequenceDiagram
participant N1 as Node A<br/>(master-eligible)
participant N2 as Node B<br/>(master-eligible)
participant N3 as Node C<br/>(master-eligible)
Note over N1,N3: 1. 检测到 master 失联
N1->>N2: RequestVote
N1->>N3: RequestVote
N2-->>N1: Vote granted
N3-->>N1: Vote granted
Note over N1: 2. 获得 quorum (2/3),当选 master
N1->>N2: Publish ClusterState
N1->>N3: Publish ClusterState
N2-->>N1: State applied
N3-->>N1: State applied
Note over N1,N3: 3. 所有节点持有一致的集群状态
Quorum 要求多数同意(N/2+1),保证同一时刻最多只有一个 master 被选出。三个 master-eligible 节点的集群中,quorum 是 2——即使一个节点故障,剩余两个仍能选出 master。
Cluster State 同步
Master 是 cluster state 的唯一写入方。任何需要修改 cluster state 的操作(创建 index、修改 mapping、shard 分配变更)都必须经过 master。
更新流程:
1 | |
任何节点收到元数据变更请求后,整个请求都要经过 master 中转,再由 master 向全集群广播新状态:
flowchart LR
Client([客户端]) -->|PUT /new-index| DataNode[Data Node]
DataNode -->|转发| Master[Master Node]
Master -->|计算新 ClusterState| Master
Master -->|广播新 State| DataNode
Master -->|广播新 State| Other[其他节点]
DataNode -->|apply| DataNode
Other -->|apply| Other
Master -->|确认完成| Client
Cluster state 的发布是全量的——每次更新都发送完整的新状态。在集群有大量 index 和 shard 时,cluster state 可能很大(几十 MB),全量发布的开销不可忽略。
自 ES 7.x 起,cluster state 发布实际上使用了增量 diff 的优化——只发送变化的部分,但逻辑语义上仍然是"每个节点维护完整的 cluster state"。
脑裂问题
脑裂(split brain)是分布式系统中的经典问题:网络分区导致集群分成两组,每组各自选出 master,独立运行,数据产生不一致。
旧版 ES(< 7.0)的脑裂风险:minimum_master_nodes 配置不当时,一个 3 节点集群在网络分区后可能两边各选出一个 master。
新版 ES(≥ 7.0)的防护机制:
- 自动管理 voting configuration 和 quorum,不需要手动配置。
- 选举需要 voting configuration 中多数节点同意,网络分区后少数派无法选出 master。
- Voting configuration 的变更本身也需要 quorum 批准,不能被单方面修改。
生产环境建议至少 3 个 dedicated master-eligible 节点。2 个节点的集群无法容忍任何一个节点故障(quorum = 2,任何一个节点故障都无法达到 quorum)。
实验
查看当前 master:
1 | |
查看 voting configuration:
1 | |
查看完整 cluster state 大小:
1 | |
模式提炼:中心化协调者 + 全量状态分发
1 | |
| 系统 | 协调者选举 | 状态分发 | 状态大小 |
|---|---|---|---|
| ES (≥7.x) | 类 Raft quorum | 全量广播(增量优化) | 随 index/shard 数增长 |
| Kafka (KRaft) | Raft | 增量日志复制 | Controller metadata |
| ZooKeeper | ZAB 协议 | 增量 watch 通知 | ZNode tree |
| etcd | Raft | 增量 watch | Key-value |
ES 的特点是"全量语义"——每个节点都持有完整的 cluster state 副本。这让任何节点都能独立做路由决策(不需要问 master),但代价是 cluster state 过大时分发开销高。
工程迁移表
| 概念 | Elasticsearch | Kafka KRaft | ZooKeeper | etcd |
|---|---|---|---|---|
| 协调者角色 | Master node | Controller | Leader | Leader |
| 选举算法 | 类 Raft (≥7.x) | Raft | ZAB | Raft |
| Quorum | N/2+1 (自动) | N/2+1 | N/2+1 | N/2+1 |
| 状态存储 | Cluster state (内存) | Metadata log | ZNode tree (内存+WAL) | Key-value (WAL) |
| 脑裂防护 | Voting configuration | Fencing token | Epoch number | Term number |
| 推荐节点数 | 3 或 5 | 3 或 5 | 3 或 5 | 3 或 5 |
常见误解
误解一:所有节点都能当 master。 只有配置了 master 角色的节点(master-eligible)才参与选举。生产环境中 data 节点通常不配置 master 角色,避免重负载的 data 节点影响选举和 cluster state 管理。
误解二:ES 7.x 使用了标准 Raft。 ES 7.x 的选举机制受 Raft 启发但不是标准 Raft 实现。它没有使用 Raft 的 log replication,cluster state 的同步走的是独立的发布机制。
误解三:master 是单点故障。 Master 是单点,但不是单点故障。当 master 故障时,集群自动从其他 master-eligible 节点中选举新 master。选举过程通常在几秒内完成。期间数据路径(搜索和写入已有 shard)仍然可用,只是元数据变更(创建新 index 等)会暂停。
练习
-
用
GET _cat/master?v查看当前 master 节点的 ID 和名称。 -
用
GET _cluster/state?filter_path=nodes查看集群中所有节点的信息,找出哪些是 master-eligible。 -
查看
GET _cluster/state/metadata的大小,理解 cluster state 包含的信息量。对一个有很多 index 的集群,这个响应可能很大。
系列导航
| 上一篇 | 下一篇 |
|---|---|
| 副本与高可用:故障恢复与读写模型 | Segment Merge 与 Index Lifecycle Management |
