1、投票部分
一个candidate向所有其他的server发送RequesetVote RPC(具体格式见论文),每次从RPC的reply中累加voteCount,如果超过一半,这个candidate变成leader,把这个消息放到channel中,反之选举失败,变成follower对应go 代码为:
if ok { //获取投票结果
if reply.VOTEGRANTED {
rf.mu.Lock()
rf.voteCount = rf.voteCount + 1
// println("rf.me: " + strconv.Itoa(rf.me) + " voteFrom: " + strconv.Itoa(server) + " voteCount: " + strconv.Itoa(rf.voteCount))
rf.mu.Unlock()
if rf.state == "candidate" && rf.voteCount > len(rf.peers)/2 {
rf.BecomeLeaderCH <- true
}
} else if reply.TERM > rf.CurrentTerm {
rf.mu.Lock()
rf.CurrentTerm = reply.TERM
rf.state = "follower"
rf.mu.Unlock()
// println(strconv.Itoa(server) + " reject " + strconv.Itoa(rf.me) + " and " + strconv.Itoa(rf.me) + " step down as follower")
如何处理放到channel中的选举结果呢?首先从channel中取出结果,如果是leader表示自己当选,修改自己状态为leader,把每个follower的nextIndex设置为当前leader的最后一个log的index(参见Raft论文),发送AppendEntries heartbeat 如果选举失败,则变成follower
func (rf *Raft) CandidateState() {
.......
select {
case <-rf.heartbeatCH://已经有人当上leader,选举失败
println("no longer panic, back to follower")
rf.state = "follower"
return
case becomeLeader := <-rf.BecomeLeaderCH: //选举成功
if becomeLeader {
rf.state = "leader"
rf.mu.Lock()
rf.NextIndex = []int{}
for i:=0; i < len(rf.peers); i++ {
rf.nextIndex = append(rf.nextIndex, len(rf.logs)-1) //把每个server 的nextIndex设置为最后一个元素
}
rf.mu.Unlock()
go rf.BroadcastAppendEntriesRPC()
return
}
default:
return //多个竞争,大家都没有当上leader,则返回,在外部循环中重新设置各个candidate定时器,再次选举
}
}