在 ETCD 源码学习过程,不会讲解太多的源码知识,只讲解相关的实现机制,需要关注源码细节的朋友可以自行根据文章中的提示,找到相关源码进行学习。
Quorum 相关介绍参考:https://blog.csdn.net/wxb880114/article/details/81604245
Quorum 在 etcd 中主要作用有两个,一是计算已被多数节点接收(Match) 的 Index。二是在进行 Leader 选举时,计算选举结果。
主要文件
/raft/quorum/majority.go 多数算法的实现。
/raft/quorum/joint.go 包含两个 majority 的结构体。第二暂时保留,当需要用的时候才会填充。 但 majority 的操作,会在 joint 重新实现,主要是变成操作两个 majority。
/raft/quorum/quorum.go 定义 quorum 的一些参数和数据结构。
源码实现
majority 数据结构
type MajorityConfig map[uint64]struct{} //MajorityConfig的定义其实就是节点集合。
计算已被多数节点接收(Match) 的 Index
func (c MajorityConfig) CommittedIndex(l AckedIndexer) Index {
n := len(c)
if n == 0 {
return math.MaxUint64
}
// stk 会在编译时生成,如果节点数不超过7,优先使用这个,效率会更高。
// 当节点数超过7个,使用 srt(动态生成)
var stk [7]uint64
var srt []uint64
if len(stk) >= n {
srt = stk[:n]
} else {
srt = make([]uint64, n)
}
{
i := n - 1
for id := range c {
if idx, ok := l.AckedIndex(id); ok {
srt[i] = uint64(idx)
i--
}
}
}
/*
这里有个程序小技巧。
插入排序, 假如有五个节点,已匹配的节点 MatchIndex 分别是 5、3、4、2、1
排序的结果为
1
2
3
4
5
n-(n/2+1) = 5-(5/2-1) = 2;
那么多数节点已配备的Match 就是数组中索引位置为2的Match
*/
insertionSort(srt)
pos := n - (n/2 + 1)
return Index(srt[pos])
}
quorum.go 定义 AckedIndexer
type AckedIndexer interface {
AckedIndex(voterID uint64) (idx Index, found bool)
}
/raft/tracker/tracker.go 具体实现 AckedIndexer
type matchAckIndexer map[uint64]*Progress
var _ quorum.AckedIndexer = matchAckIndexer(nil)
// AckedIndex implements IndexLookuper.
func (l matchAckIndexer) AckedIndex(id uint64) (quorum.Index, bool) {
pr, ok := l[id]
if !ok {
return 0, false
}
return quorum.Index(pr.Match), true
}
计算 Leader 选举结果
func (c MajorityConfig) VoteResult(votes map[uint64]bool) VoteResult {
if len(c) == 0 {
return VoteWon
}
/*
ny[0] 累计投票给当前节点的总数
ny[1] 累计拒绝投票给当前节点的总数
*/
ny := [2]int{}
var missing int
for id := range c {
v, ok := votes[id]
if !ok {
missing++
continue
}
if v {
ny[1]++
} else {
ny[0]++
}
}
q := len(c)/2 + 1
//超过一半则选举成功
if ny[1] >= q {
return VoteWon
}
//等待其他节点投票
if ny[1]+missing >= q {
return VotePending
}
//选举失败
return VoteLost
}
在进行Leader选举时, /ratf/tracker/tracker.go 会通过 TallyVotes 调用该函数,计算选举结果。
joint 数据结构
type JointConfig [2]MajorityConfig
JointConfig 与 MajorityConfig 实现的功能相似,只是从计算一个 MajorityConfig 变成 计算两个 MajorityConfig。
PS:欢迎纠正