一个 Elasticsearch 集群里,master 节点负责管理集群状态(有哪些索引、分片分配在哪、哪些节点还活着)。master 只能有一个——两个 master 同时拍板会导致集群状态分裂("裂脑")。这篇讲清楚多个节点怎么在没有人工介入的情况下,自己选出唯一一个 master,以及网络出问题时怎么保证不会选出两个。
这篇的核心算法用可验证的仿真复现,并且用一段本机真实记录下的日志作为佐证——这行日志是这台机器在准备这个系列时,一次真实(虽然最终因为内存不足没能完整跑起来)的三节点集群引导尝试留下的。
Elasticsearch 从 7.0 开始用一套自研的、类 Raft 的协调协议(替代更早的 Zen Discovery)。规则很简单,但这个简单规则本身就是防止裂脑的全部秘密。
类似上一篇 primary_term 的思路——每发起一轮新的选举,term 加一,用来区分"这是哪一轮达成的结果"。
N 个有资格当 master 的节点里,候选人要拿到 ⌊N/2⌋+1 票才能当选——不是"票数最高就行",是必须过半。
把 N 个节点分成两拨,不可能两拨都同时超过半数——这就是为什么"严格多数"这个条件,本身就杜绝了两个 master 同时存在的可能性。
准备这篇文章时,曾经真实尝试过在本机拉起一个三节点集群做实验——受限于这台机器当前可用内存,第二、第三个节点的 Elasticsearch 进程在完成启动前就被系统终止了,三节点集群最终没能完整组建起来。但第一个节点在等待另外两个节点加入的过程中,留下的日志是真实的:
这行日志里的 node term、last-accepted version 不是文档里的示意,是这台机器上真实运行的 Elasticsearch 进程,真实按照这套术语记录自己的协调状态——即便这次实验最终因为资源不足没能凑齐三个节点完整选出 master,这段日志本身已经如实证明了"基于 term 的状态追踪"在这台机器上是真实生效的机制,不是文档里的一面之词。这个限制本身也如实记录在这里,没有假装做出了一次成功的三节点选举。
用一个可验证的三节点模型(node1/node2/node3,全部有资格当选)复现完整过程。
verified simulation 场景:term 1,三节点全部在线,一致选出 node1;node1 故障下线;term 2,剩下的 node2/node3(2/3,够多数)选出 node2;这时网络分区,node2 只能看到自己(1/3,不够多数)——term 3 选举失败,没有新 master 产生,不会有节点错误地自认为是 master;node1 恢复上线;term 4,三节点重新形成多数,选出 node3。
quorum 公式 ⌊N/2⌋+1 直接决定了这件事——不是习惯,是算出来的。
| 节点数 N | quorum | 能容忍几个节点失效 |
|---|---|---|
| 3 | 2 | 1 |
| 4 | 3 | 1 |
| 5 | 3 | 2 |
| 6 | 4 | 2 |
3 台和 4 台能容忍的失效数量完全一样(都是 1 台)——多出来的第 4 台没有换来任何额外的容错能力,纯粹是多花一份成本。5 台比 4 台反而更划算(容错从 1 提升到 2),这也是为什么"3 或 5"是最常见的 master 候选节点数量,"4"这种偶数配置在实践中很少见。