Elasticsearch 中如何防止脑裂?
在 Elasticsearch (ES) 中,“脑裂”(Split-Brain)是指由于网络分区(Network Partition)或其他通信故障,导致一个集群中分裂出两个或多个相互独立的“子集群”,并且每个子集群都选出了自己的 Master 节点。这会导致数据不一致、数据丢失或由于并发写入导致的冲突。
防止脑裂的方法主要取决于你使用的 Elasticsearch 版本,因为在 7.0 版本中,ES 的集群协调层(Cluster Coordination)发生了重大重构。
以下是针对不同版本的详细解决方案:
1. Elasticsearch 7.x 及更高版本 (推荐)
在 ES 7.0 之后,官方移除了旧的 Zen Discovery 机制,引入了新的集群协调子系统(基于 Raft 共识算法的变体)。在这个版本中,ES 会自动处理仲裁(Quorum),你不再需要手动配置 minimum_master_nodes。
核心机制
ES 7.x 通过投票配置(Voting Configuration)来管理主节点选举。集群会自动维护一份可以参与投票的节点列表。只有获得列表中过半数节点投票的候选者才能成为 Master。
如何配置防止脑裂
- 移除旧配置:不要再设置
discovery.zen.minimum_master_nodes,该参数在 7.x 中已被废弃并忽略。 - 设置初始主节点 (Bootstrapping):
- 在集群首次启动时,必须在配置文件
elasticsearch.yml中配置cluster.initial_master_nodes。 - 这个参数告诉集群在第一次启动时,哪些节点有资格参与选举并形成初始集群。
- 注意:一旦集群形成,后续重启或添加节点时,不要再依赖或修改此参数(虽然保留它通常无害,但它只在第一次引导时起作用)。
- 配置示例:yaml
cluster.initial_master_nodes: ["node-1", "node-2", "node-3"]
- 在集群首次启动时,必须在配置文件
- 节点数量建议:依然建议 Master-eligible(有资格成为主节点)的节点数量为奇数(如 3 个),以便容错。
2. Elasticsearch 7.x 之前版本 (6.x, 5.x 等)
在旧版本中,防止脑裂的核心在于手动配置“法定人数”(Quorum)。
核心配置:discovery.zen.minimum_master_nodes
这是防止脑裂的最关键参数。它的含义是:一个节点要成为 Master,或者一个 Master 要维持其地位,必须“看到”多少个 Master-eligible 节点(包括它自己)。
公式
N / 2 + 1
- N = 集群中
node.master: true(有资格成为主节点) 的节点总数。 - 该公式确保了在网络分裂时,只有拥有“多数派”节点的那一部分集群才能选举出 Master,而少数派节点会停止服务或尝试重新加入。
举例
假设你有 3 个 Master-eligible 节点:
- 计算:3 / 2 + 1 = 1.5 + 1 = 2.5,取整为 2。
- 配置:
discovery.zen.minimum_master_nodes: 2
场景推演:
如果网络断开,节点 A 和 B 在一边,节点 C 在另一边:
- A+B 侧:有 2 个节点,满足
minimum_master_nodes: 2,可以选举 Master,集群正常工作。 - C 侧:只有 1 个节点,不满足 2,无法选举 Master,节点 C 会停止写入服务,直到网络恢复。
- 结果:只有一个 Master,防止了脑裂。
3. 通用的最佳架构实践 (适用于所有版本)
除了上述配置外,合理的架构设计也是防止脑裂的关键:
使用奇数个 Master 节点:
- 最常见的配置是 3 个 专用的 Master 节点。
- 如果是 2 个节点,一旦断网,任何一方都无法凑齐“大多数”(2/2+1=2),导致集群不可用。
- 如果是 3 个节点,允许挂掉 1 个;如果是 5 个,允许挂掉 2 个。
角色分离 (Dedicated Master Nodes):
- 在生产环境的大型集群中,建议将 Master 节点与 Data 节点分离。
- Master 节点:
node.master: true,node.data: false。只负责集群状态管理(索引创建、节点管理),不负责存储数据和繁重的搜索计算。 - Data 节点:
node.master: false,node.data: true。 - 原因:防止因为数据节点负载过高(GC 停顿、CPU 满载)导致 Master 节点假死,从而误触发重新选举。
调整网络超时参数:
- 如果网络环境不稳定,可以适当增加节点间 Ping 的超时时间,避免因为短暂的网络抖动导致误判节点掉线。
- 参数:
discovery.zen.ping_timeout(旧版本) 或transport.connect_timeout等。
总结
- ES < 7.0:必须严格遵守
N/2 + 1公式,配置discovery.zen.minimum_master_nodes。 - ES >= 7.0:依靠内部共识算法自动处理,只需在集群首次启动时正确配置
cluster.initial_master_nodes,并保持 Master 候选节点为奇数个(通常为 3 个)。