关于 QuoRuM 的两个维度
本文聚焦 etcd 在实现 Quorum 时的两个核心维度及其含义,而非全面框架细节,帮助理解选举与日志提交在集群中的角色。
QuoRuM 的本质属于多数派(大多数节点)的应用。它在两个方面体现:一是选举过程,只有获得多数投票的节点才会成为 Leader;二是运行过程,被多数节点提交(COMMIT)的日志位置才算在集群中可靠记录,之后的应用才会对外可见。
基于此,存在两个需要思考的问题:
1) 既然是选举过程,票数如何投出并统计?
2) 既然是运行过程,集群中的节点如何对齐日志的提交位置?
有选举自然就有点票。选举过程是小组内的一次投票环节,类似过去选班干部时在黑板上写出结果,票数多的同学当选。
etcd 的 Leader 选举也是如此。Leader 的胜出依赖于票数达到多数,即满足 Quorum 机制的条件。
下面我们具体看看 etcd 如何进行唱票(投票)?
思路其实很简单:统计每位参与选举节点的投票情况,票数超过半数即为胜出。
举例:有 A、B、C、D、E 五位候选节点参与竞选,当某个候选者获得 3 张票时即可成为 Leader。
下面进入 etcd 的唱票实现细节。
选举属于 QuoRuM 机制的一部分,相关实现代码位于 etcd/Raft/quoRuM/ 目录下。QuoRuM 的核心实现集中在 MajoritYConfig 结构体中,实质是对一个映射(Map)的封装:
该 Map 的键(key)代表集群中节点的标识,映射的值并不关键,使用了 stRUCt 对象来存储信息。
一个小思考:既然值不重要,为什么不直接用切片(slice)来存储?
原因在于查找需求。Map 的查询时间复杂度是常数级,而值使用的结构体不占额外空间,兼顾了查询效率和内存占用。
// etcd/Raft/quoRuM/Majority.go 中的 VoteResult 函数示例:
func (c MajorityConfig) VoteResult(votes Map[uint64]bool) VoteResult {
// 构造一个长度为 2 的数组 ny := [2]int{}
// 遍历集群节点 for id := Range c {
v, ok := votes[id]
if !ok {
// 暂时没投票的 MiSSing++
continue
}
if v {
// 投票赞同的 ny[1]++
}
// 其余逻辑略去,保留核心思想
}
// 最终返回结果(胜出与否及统计信息)
}
通过上述设计,QuoRuM 将投票结果快速汇聚,并据此判断 Leader 是否产生,以及集群在后续日志提交中的领导权分配。
