找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1800

积分

0

好友

238

主题
发表于 8 小时前 | 查看: 3| 回复: 0

很多人学习 Raft 协议时,都会产生一个疑问:Elasticsearch 的 Master 选举是不是 Raft?

答案很明确:

现在的机制非常像 Raft,但早期完全不是。而且,早期选主机制还引发过不少线上事故。

今天,我们就从真实的工程问题出发,深入剖析 Elasticsearch 选主机制的演进之路,讲清楚它是如何一步步变得健壮的。

一、分布式系统的噩梦:什么是“脑裂”?

在分布式系统里,最可怕的故障往往不是节点宕机,而是:

同时出现两个 Master

这种情况被称为 Split Brain(脑裂)

一旦发生脑裂,集群会陷入混乱:

  • 两个 Master 可能同时修改集群状态。
  • 数据分片可能被冲突地分配到不同节点。
  • 集群的元数据(Metadata)会出现不一致。
  • 故障恢复时,极有可能导致数据丢失。

在 Elasticsearch 6.x 及更早的版本中,脑裂问题并不少见。

二、早期的设计:Zen Discovery 与手动配置

在 7.0 版本之前,Elasticsearch 使用一套名为 Zen Discovery 的模块来处理节点发现与 Master 选举。

它的核心思想听起来很合理:多数派(Quorum)选举。即,一个节点必须得到超过半数的 Master-eligible 节点同意,才能成为 Leader。

但这个机制依赖于一个至关重要的手动配置项:

discovery.zen.minimum_master_nodes

这个参数具体怎么用?我们来模拟一个场景。

假设你的集群有 3 个具备 Master 资格的节点。此时,minimum_master_nodes 的正确配置应该是:

minimum_master_nodes = 2

它的计算公式是 (N / 2) + 1,其中 N 是 Master-eligible 节点的总数。

如果这个参数配错了,比如设置成了 1,危险就来了。当发生网络分区(Network Partition)时:

A   |   B C

节点 A 在一侧,节点 B 和 C 在另一侧。由于 minimum_master_nodes=1A 可以自举为 Master,B 和 C 这一侧也能成功选出一个 Master

于是,集群中出现了两个“合法”的 Master:

两个 Master 同时存在

脑裂就此发生。

三、为何说这个设计是“危险”的?

关键在于,Zen Discovery 将集群安全的基石,完全寄托于“人工配置的正确性”。而在复杂的工程实践中,手动参数恰恰是最容易出错的环节:

  • 集群扩容时,忘记更新此参数。
  • 集群缩容时,同样忘记修改。
  • 测试环境的配置错误地同步到了生产环境。
  • 运维人员对计算公式理解有误。

历史上大量的 Elasticsearch 线上稳定性事故,都与 discovery.zen.minimum_master_nodes 配置不当有关。这促使 Elastic 官方在 7.x 版本中下决心重构整个协调子系统。

四、Elasticsearch 7.x 的重构:走向“类 Raft”

从 7.0 版本开始,Elasticsearch 彻底重写了负责选主和元数据一致性的子系统,并将其命名为 Cluster Coordination Subsystem

官方文档明确指出,其设计 灵感来源于 Raft 协议(Inspired by Raft)

请注意这里的措辞:是“借鉴灵感”而非“完全实现”。它吸收了 Raft 中关于安全性的核心思想,并针对 Elasticsearch 自身的数据模型和运维场景做了大量工程化裁剪。

五、新版选主机制的核心思想

让我们拆解一下这套新机制的几个关键点,它与 Raft 协议的相似之处一目了然。

1️⃣ 引入任期(Term)概念

和 Raft 完全一致,每一次新的选举周期都会产生一个递增的 Term 编号。

term + 1

一个旧任期的节点,无论因为什么原因(如网络延迟、进程暂停)重新加入集群,都无法再成为合法的 Master。这有效防止了“旧主复活,覆盖新状态”的问题。

2️⃣ 严格的多数派投票制

一个节点想要成为 Master,必须获得当前投票配置(Voting Configuration)中超过半数的节点投票。这是保证同一任期内最多只有一个 Leader 的根本原则。

3️⃣ 移除 minimum_master_nodes 手动配置

这是最具工程意义的一步。在 7.x 之后,你不再需要手动计算和配置这个参数。系统会根据当前的 Voting Configuration 自动判定多数派。

这从根本上消除了因人工配错而导致脑裂的可能性。

4️⃣ 引入投票配置(Voting Configuration)

这是一个工程上的优化设计。每当集群拓扑发生变更时——例如增加或移除 Master 节点——都会生成一个新的 Voting Configuration

Voting Configuration

它明确记录了在当前任期内,哪些节点拥有投票权。这类似于 Raft 协议中的集群成员变更(Membership Change)机制,但实现上更贴合 Elasticsearch 自身的管理 API 和运维习惯。

5️⃣ 发布-确认的提交机制

新选出的 Master(称为 Elected Master)并不会立即行使权力。它必须完成一个关键步骤:

向多数节点发布新的 Cluster State

并等待这些节点的确认(Ack)。只有在收到足够多的确认,即该状态被“提交”后,它才正式成为活跃的 Master(Active Master)。

这个机制与 Raft 中 Leader 将日志复制到多数节点后才提交(Commit)的模型非常相似。

六、一次完整的选举流程(工程视角)

当活跃 Master 失效后,集群的选举流程可以概括为以下几步:

Step 1:节点成为候选人
检测到 Master 失联的节点会自增 Term,并进入 Candidate 状态,向其他投票节点发起投票请求。

Step 2:节点投票逻辑
一个节点在收到投票请求后,会基于以下条件决定是否投票:

  • 自己在本任期尚未投过票。
  • 请求方的 Term 不低于自己已知的 Term。
  • 请求方所知的集群状态不落后于自己。

Step 3:赢得选举
某个候选人如果获得了超过半数的投票,即成为“当选 Master”(Elected Master)。

Step 4:发布并确认集群状态
当选 Master 将包含新任期和自己身份的集群状态发布出去,并等待多数节点的确认。

Step 5:正式履职
在获得足够确认后,当选 Master 转变为活跃 Master,开始接收和处理各类集群操作请求,如索引创建、分片分配、Mapping 更新等。

七、与标准 Raft 协议的关键差异

尽管高度相似,但 Elasticsearch 的协调机制并非标准的 Raft 实现,主要区别在于:

① 复制对象不同

  • Raft:复制的是顺序化的操作日志,通过日志来驱动所有状态机(如 MySQL、Redis 等)达成一致。
  • Elasticsearch:主要对 Cluster State(集群状态,即元数据) 做一致性控制。而真正的数据分片(Shard)本身,是通过主副分片间的同步(Replication)机制来保证的。

② 协议范围不同

  • Raft:是一个通用的状态机复制协议
  • Elasticsearch:是一个专注于元数据一致性的协议,范围更聚焦。

③ 工程优化侧重点不同
Elasticsearch 的设计优先考虑了自身场景的工程稳定性:

  • 快速启动与恢复:优化选举速度和节点加入流程。
  • 耐受网络抖动:在网络不稳定时能更快恢复服务。
  • 绝对避免脑裂:这是设计的核心红线。
  • 自动化与安全性:减少人工干预,防止配置错误。

八、为什么说现在“非常像 Raft”?

因为它完整具备了 Raft 协议中保证安全性的几个核心要素:

  • 任期(Term)
  • 领导者选举必须获得多数派投票
  • 状态提交需经多数派确认
  • 安全的集群成员变更管理

但它也缺失了 Raft 作为通用协议的一些组成部分:

  • 通用的、顺序化的操作日志复制模型。
  • 严格的 Leader 追加日志(Append-Entries)的同步方式。
  • 完整的状态机抽象。

因此,更准确的定位是:一个深受 Raft 启发、为解决元数据一致性而深度工程化的“类 Raft”集群协调协议

九、现在的 Elasticsearch 还会脑裂吗?

在 7.x 及之后的版本中,在正常的网络模型和运维操作下,几乎不可能发生脑裂

原因就在于上述机制的保证:

  • 选主必须获得自动计算的多数派同意。
  • 严格的任期校验阻止旧主干扰。
  • 任何集群状态变更都需要多数派确认后才能生效。

这套机制在实践中已经非常成熟和稳定。

十、总结与启示

Elasticsearch 集群协调机制的演进历程,给了我们一个深刻的工程启示:

经典的理论协议不等于最终的工程实现。一个成熟的工程系统,必须根据自身的核心诉求进行合理的场景裁剪。

它没有盲目照搬 Raft,而是:

  1. 精准识别核心问题:对于 Elasticsearch,核心是保证集群元数据(Cluster State)的一致性,而非所有数据。
  2. 借鉴安全性原则:牢牢抓住 Raft 中关于选举安全、提交安全的核心思想。
  3. 进行深度工程优化:移除易错的手动配置,设计更贴合自身运维模式的成员管理,优化恢复速度。

这种“取其神,塑其形”的设计方式,正是构建稳定、可靠分布式系统的成熟思路。对于开发者而言,理解这种从理论到实践的落地过程,比单纯学习协议本身更有价值。如果你想了解更多分布式系统设计背后的权衡与细节,欢迎来 云栈社区 与大家一起交流探讨。




上一篇:深入解析ZAB协议:ZooKeeper为何选用原子广播而非Paxos/Raft?
下一篇:亿级视频排行榜架构设计:基于Redis、Kafka与滑动时间窗口的实战方案
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-3-3 21:13 , Processed in 0.483502 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表