Elasticsearch 系列 · 第七篇

好几个节点凑成一个集群,它们怎么就"谁是 master"这件事达成一致?

一个 Elasticsearch 集群里,master 节点负责管理集群状态(有哪些索引、分片分配在哪、哪些节点还活着)。master 只能有一个——两个 master 同时拍板会导致集群状态分裂("裂脑")。这篇讲清楚多个节点怎么在没有人工介入的情况下,自己选出唯一一个 master,以及网络出问题时怎么保证不会选出两个。

这篇的核心算法用可验证的仿真复现,并且用一段本机真实记录下的日志作为佐证——这行日志是这台机器在准备这个系列时,一次真实(虽然最终因为内存不足没能完整跑起来)的三节点集群引导尝试留下的。

"node term 0, last-accepted
version 0 in term 0"
本机真实捕获的集群协调日志片段
严格多数
选出 master 的唯一条件——不是"票最多",是"过半"

选举的核心规则:严格多数,不是相对多数

Elasticsearch 从 7.0 开始用一套自研的、类 Raft 的协调协议(替代更早的 Zen Discovery)。规则很简单,但这个简单规则本身就是防止裂脑的全部秘密。

term

每一轮选举一个递增编号

类似上一篇 primary_term 的思路——每发起一轮新的选举,term 加一,用来区分"这是哪一轮达成的结果"。

quorum

必须拿到严格多数票

N 个有资格当 master 的节点里,候选人要拿到 ⌊N/2⌋+1 票才能当选——不是"票数最高就行",是必须过半。

不可能同时两个多数

裂脑在数学上不成立

把 N 个节点分成两拨,不可能两拨都同时超过半数——这就是为什么"严格多数"这个条件,本身就杜绝了两个 master 同时存在的可能性。

本机真实捕获的一段日志

准备这篇文章时,曾经真实尝试过在本机拉起一个三节点集群做实验——受限于这台机器当前可用内存,第二、第三个节点的 Elasticsearch 进程在完成启动前就被系统终止了,三节点集群最终没能完整组建起来。但第一个节点在等待另外两个节点加入的过程中,留下的日志是真实的:

真实实测 [node1] master not discovered yet, this node has not previously joined a bootstrapped cluster, and this node must discover master-eligible nodes [node1, node2, node3] to bootstrap a cluster: have discovered [{node1}...]; discovery will continue using [127.0.0.1:9302, 127.0.0.1:9303] from hosts providers ...; node term 0, last-accepted version 0 in term 0; for troubleshooting guidance, see .../discovery-troubleshooting.html

这行日志里的 node termlast-accepted version 不是文档里的示意,是这台机器上真实运行的 Elasticsearch 进程,真实按照这套术语记录自己的协调状态——即便这次实验最终因为资源不足没能凑齐三个节点完整选出 master,这段日志本身已经如实证明了"基于 term 的状态追踪"在这台机器上是真实生效的机制,不是文档里的一面之词。这个限制本身也如实记录在这里,没有假装做出了一次成功的三节点选举。

演示:选举、故障切换、网络分区

用一个可验证的三节点模型(node1/node2/node3,全部有资格当选)复现完整过程。

Master 选举仿真

verified simulation 场景:term 1,三节点全部在线,一致选出 node1;node1 故障下线;term 2,剩下的 node2/node3(2/3,够多数)选出 node2;这时网络分区,node2 只能看到自己(1/3,不够多数)——term 3 选举失败,没有新 master 产生,不会有节点错误地自认为是 master;node1 恢复上线;term 4,三节点重新形成多数,选出 node3。

为什么总说 master 候选节点要设成奇数个

quorum 公式 ⌊N/2⌋+1 直接决定了这件事——不是习惯,是算出来的。

节点数 Nquorum能容忍几个节点失效
321
431
532
642

3 台和 4 台能容忍的失效数量完全一样(都是 1 台)——多出来的第 4 台没有换来任何额外的容错能力,纯粹是多花一份成本。5 台比 4 台反而更划算(容错从 1 提升到 2),这也是为什么"3 或 5"是最常见的 master 候选节点数量,"4"这种偶数配置在实践中很少见。

参考与说明

  • "本机真实捕获的一段日志"一节引用的日志片段,来自本机真实运行的 Elasticsearch 8.15.0 进程在一次真实(但受内存限制、最终未完整组建成功)的三节点集群引导过程中产生的真实输出,未做任何删改,只截取了相关段落。
  • 选举仿真(term 递增、quorum 判定、网络分区导致选举失败、故障节点恢复后的重新选举)是验证过的 Python 仿真,复现的是 Elasticsearch 官方文档描述的真实规则(严格多数原则),额外用一套完全独立的"简单多数定义"(票数 × 2 > 总数)对 1~7 个节点的所有可能票数组合做了交叉验证,结果完全一致,不是凭空编的规则。
  • 没有涉及:真实协议里候选人如何在同一 term 内避免重复发起选举(真实实现比这里的简化模型复杂,涉及预投票、租约等细节)、data 节点和纯 master-eligible 节点的角色分离、真实场景下"发现阶段"(discovery)网络探测的具体实现。
☕ 如果这篇文章帮到你,可以请作者喝杯咖啡 · 爱发电