上一篇解决了副本机制和故障恢复——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
2
3
4
5
1. 当前 master 失联(或集群初始启动)
2. Master-eligible 节点发起选举
3. 候选节点请求其他 master-eligible 节点投票
4. 获得 voting configuration 中多数票(quorum)的节点成为新 master
5. 新 master 发布 cluster state 给所有节点

整个选举到状态发布的流程可以拆成四个阶段:

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
2
3
4
5
6
操作请求(如 PUT /new-index)
→ 转发到 master 节点
→ Master 计算新的 cluster state
→ Master 将新 cluster state 发布给所有节点
→ 每个节点 apply 新 state
→ Master 确认更新完成

任何节点收到元数据变更请求后,整个请求都要经过 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
GET _cat/master?v

查看 voting configuration:

1
GET _cluster/state/metadata?filter_path=metadata.cluster_coordination

查看完整 cluster state 大小:

1
GET _cluster/stats?filter_path=indices.count,indices.shards.total

模式提炼:中心化协调者 + 全量状态分发

1
election → single leader → leader writes state → broadcast to all → nodes apply
系统 协调者选举 状态分发 状态大小
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 等)会暂停。

练习

  1. GET _cat/master?v 查看当前 master 节点的 ID 和名称。

  2. GET _cluster/state?filter_path=nodes 查看集群中所有节点的信息,找出哪些是 master-eligible。

  3. 查看 GET _cluster/state/metadata 的大小,理解 cluster state 包含的信息量。对一个有很多 index 的集群,这个响应可能很大。

系列导航

上一篇 下一篇
副本与高可用:故障恢复与读写模型 Segment Merge 与 Index Lifecycle Management

参考资料