脑裂问题:从原理到预防

22 May 2026 – wusfe · 5 min read

脑裂问题:从原理到预防

一、脑裂是什么

脑裂(Split-Brain)指在一个 Elasticsearch 集群中同时出现了两个或多个 Master 节点,各自认为自己是唯一的 Master,各自独立接收写入操作。

正常状态:        [Master] -- [Data Node 1] -- [Data Node 2]

脑裂状态:        [Master A] -- [Data Node 1]     (网络分区)
                  [Master B] -- [Data Node 2]

两个 Master 各自认为对方已离线,各自都接收写入。

本质原因:Master 选举机制在网络分区场景下产生了两个或多个多数派,或仲裁条件未能阻止少数派独立运行。

二、脑裂的后果

2.1 数据不一致

时间线:
T1: 网络分区,Master A 和 Master B 并存
T2: 用户 A 写入 doc_1 到 Master A 的集群 → doc_1 在 shard_0 上
T3: 用户 B 写入 doc_2 到 Master B 的集群 → doc_2 也在 shard_0 上
T4: 网络恢复,两个 Master 重新选举
T5: Master B 被降级为普通节点,Master A 的 shard_0 覆盖了 Master B 的 shard_0
T6: doc_2 永久丢失!

2.2 索引冲突

两个 Master 各自创建/删除索引、调整 mapping 设置,网络恢复后索引状态可能出现无法预测的冲突:

  • 同一个索引在两个分区上被修改了不同的 mapping。
  • 一个分区上删除了的索引在另一个分区上仍然存活。
  • 分片分配策略互相矛盾。

2.3 资源浪费

两个 Master 各自管理分片分配,可能导致同一个分片在各自的节点组中被多次分配,造成磁盘和内存浪费。

三、ES 6.x / 7.x 前:Zen Discovery 与最小主节点数

3.1 Zen Discovery 的选举机制

6.x 及之前版本使用 Zen Discovery 协议进行 Master 选举。核心配置:

# elasticsearch.yml
discovery.zen.minimum_master_nodes: 2        # 最小主节点数
discovery.zen.ping.unicast.hosts:             # 候选 Master 节点
  - 10.0.0.1:9300
  - 10.0.0.2:9300
  - 10.0.0.3:9300

3.2 minimum_master_nodes 公式

minimum_master_nodes = N / 2 + 1

其中 N 是有资格成为 Master 的节点数(node.master: true)。

集群 Master 节点数 minimum_master_nodes 能容忍的故障节点数
1 1 0(单点故障)
2 2 0(无法容忍任何故障)
3 2 1
4 3 1
5 3 2
6 4 2

关键规则

  • Master 节点数必须是奇数
  • 偶数个 Master 节点和奇数个 Master 节点的容错能力相同(2 和 3 都能容忍 0 个和 1 个故障),但偶数会增加脑裂风险。

3.3 脑裂是如何发生的

假设 4 个 Master 节点,minimum_master_nodes = 2(如果运维配错了):

网络分区:A、B 互通,C、D 互通。A、B 之间无法与 C、D 通信。

分区 1:A、B 两个节点 → 2 >= minimum_master_nodes(2) → 可以选举 Master
分区 2:C、D 两个节点 → 2 >= minimum_master_nodes(2) → 也可以选举 Master

脑裂发生!

正确配置 minimum_master_nodes = 3(4/2+1=3):

分区 1:A、B → 2 < 3 → 无法达到 quorum → 不会选举 Master
分区 2:C、D → 2 < 3 → 同上

两个分区都无法选举 Master → 集群不可用,但不会脑裂!

宁可不可用,也不能让集群脑裂。 不可用是暂时性的,数据不会丢;脑裂会导致数据永久不一致。

四、ES 7.x 后:新的集群协调层

ES 7.0 重构了集群协调(Cluster Coordination)层,废弃了 Zen Discovery。

4.1 新的配置方式

# elasticsearch.yml (ES 7.x+)
cluster.name: my-cluster
node.name: node-1

# 种子节点列表:集群启动时发现的初始节点
discovery.seed_hosts:
  - 10.0.0.1:9300
  - 10.0.0.2:9300
  - 10.0.0.3:9300

# 初始 Master 节点:首次启动时参与投票的节点
cluster.initial_master_nodes:
  - node-1
  - node-2
  - node-3

4.2 新旧对比

配置项 ES 6.x (Zen Discovery) ES 7.x+ (New Coordination)
节点发现 discovery.zen.ping.unicast.hosts discovery.seed_hosts
首次选举 discovery.zen.minimum_master_nodes cluster.initial_master_nodes
投票配置 静态配置 自动维护(Voting Configuration)
脑裂防护 minimum_master_nodes 手动设置 自动维护 quorum,无需手动设置

4.3 重要区别

cluster.initial_master_nodes 仅在集群首次启动时使用。一旦集群成功形成,投票配置就持久化到了集群状态中。后续节点加入不会再用到这个配置。

这意味着:

  • 向已有集群添加新节点时,不需要将其加入 cluster.initial_master_nodes
  • 如果集群所有 Master 节点同时挂掉(旧集群状态丢失),需要使用 elasticsearch-node unsafe-bootstrap 工具恢复。

五、网络分区场景深度分析

场景一:交换机故障导致数据中心内部分区

机架 A:node-1 (master), node-2
机架 B:node-3, node-4, node-5
机架间交换机故障 → node-1, node-2 与其余节点隔离

- ES 6.x + minimum_master_nodes=3 正确配置:
  node-1, node-2 → 2/5 < 3 → 分区不能选举新 Master → 原有 Master (node-1) 发现自己失去 quorum → 自动降级 → 集群不可用,但无脑裂

- ES 7.x+ 同样行为:失去 quorum 的 Master 自动降级

场景二:跨数据中心网络分区

DC1:node-1, node-2, node-3 (3 个 Master 节点)
DC2:node-4, node-5, node-6 (3 个数据节点)

DC1 和 DC2 之间网络中断:
- DC1 有 3 个 Master 节点,可以形成 quorum,继续运行。
- DC2 的数据节点发现无法联系 Master,处于"无主"状态,拒绝写入。
- 网络恢复后,DC2 节点重新加入集群,数据完整。

场景三:单播配置遗漏

# 错误配置:node-3 的 unicast hosts 中漏掉了 node-2
# node-1: discovery.zen.ping.unicast.hosts: [node-1, node-2, node-3]
# node-2: discovery.zen.ping.unicast.hosts: [node-1, node-2, node-3]
# node-3: discovery.zen.ping.unicast.hosts: [node-1, node-3]        ← 漏了 node-2!

结果:如果 node-1 挂了,node-2 和 node-3 无法互相发现 → 各自选举 Master → 脑裂!

六、预防措施总结

措施 版本 说明
奇数个 Master 节点 全版本 3 或 5 个,绝不使用 2 或 4 个
minimum_master_nodes = N/2+1 6.x 及以下 防止少数派独立成主
种子节点列表完整 全版本 每个节点的种子/单播列表必须包含所有候选 Master
使用专用 Master 节点 全版本 让 Master 节点只做管理,不做数据存储(node.master: true, node.data: false
升级到 ES 7.x+ 7.x+ 自动维护 quorum,减少配置错误
网络冗余 运维层 避免单点网络故障导致大面积分区
监控 Master 节点数 运维层 当 Master 节点数变化时立即告警

七、踩坑案例

案例 1:扩容后忘记更新 minimum_master_nodes

某团队将集群从 3 个 Master 节点扩展到 5 个,但忘了更新 minimum_master_nodes(仍为 2)。一次网络抖动导致 2 个节点与剩余 3 个节点暂时隔离——这 2 个节点发现自己满足 quorum(2 >= 2),选举了新的 Master,脑裂发生。网络恢复后,两个 Master 的数据发生冲突,导致一个索引的 mapping 损坏,最终通过 snapshot 恢复到脑裂前的状态,丢失了 4 小时的数据。

教训:每次变更 Master 节点数后,必须同步更新 minimum_master_nodes

案例 2:跨机房部署,专线故障引发脑裂

某公司 ES 集群跨两个机房部署(每个机房 3 个 Master 节点)。专线中断后,两个机房各自的 3 个 Master 节点都能满足 quorum(3 >= 4 的 quorum),各自选举了 Master。恢复后数据产生严重冲突。

教训:跨机房部署 ES 集群不推荐。如果必须跨机房,应该确保 Master 节点集中在其中一个机房(或使用跨集群搜索 CCS / 跨集群复制 CCR 替代)。

八、排查脑裂的方法

# 检查集群中是否有多个 Master 节点自称当前 Master
GET /_cat/nodes?v&h=name,node.role,master,version

# 查看集群状态变化历史
GET /_cluster/state/_all

# 在日志中搜索关键词
# grep "master.*elected" /var/log/elasticsearch/*.log
# 如果短时间内出现多次 "master elected" 日志,很可能是脑裂
# 每个节点的日志中检查
grep -i "detected_master" /var/log/elasticsearch/my-cluster.log
grep -i "master_left" /var/log/elasticsearch/my-cluster.log

一旦发现脑裂,立即停止所有节点的写入操作(可通过 API 设置 index.blocks.write: true),然后从最小的那个分区(节点最少的那个 Master 所在的分区)强制重启,让节点重新加入多数派分区。