Lab2A:(领导选举)
实施Raft领导者选举和心跳(AppendEntries RPCs,无日志条目)。第二部分A的目标是选出一个单一的领导者,如果无故障,领导者继续担任领导者,如果老领导者出现故障或者与老领导者的通信丢失,新领导者将接管。运行go test -run 2A测试你的2A代码。
提示:
-
利用go test -run 2A测试(- race)
-
看图2
-
Raft结构体添加
-
填写RequestVoteArgs和RequestVoteReply结构。修改Make()以创建一个后台goroutine,当它有一段时间没有收到另一个对等方的消息时,通过发送RequestVote RPC来定期启动领导人选举。通过这种方式,如果已经有领导者,同龄人将了解谁是领导者,或者自己成为领导者。实现RequestVote()RPC处理程序,以便服务器相互投票
-
要实现检测信号,请定义AppendEntries RPC结构(尽管您可能还不需要所有参数),并让leader定期发送它们。编写一个AppendEntries RPC处理程序方法,该方法重置选举超时,以便其他服务器在一个服务器已经当选时不会作为领导者介入
-
确保不同节点的选举超时不会总是同时进行,否则所有同行都只投票给自己,没有人会成为领导者。——利用随机的选举超时
-
测试人员要求领导者每秒发送心跳RPC的次数不超过10次
-
测试要求,在Leader故障后的五秒内,你的Raft需要选出新领导。
-
使用sleep进行定时器的实现;time.trciker的实现比较复杂。
-
不要忘记实现Getstate方法
-
rf.killed()被调用时Kill()是否被调用
-
RPC的参数都要进行导出
踩的坑:
统计选票
统计选票的时候未排除任期小于当前任期票,导致任期小的票扰乱当前选票,导致一轮选票下来有多个Leader
if reply.VoteGranted && reply.Term == rf.CurrentTerm { *voteNum += 1 }
心跳加选票的请求都要排除自己:
Leader不应该给自己发送心跳,一发心跳直接将Leader状态给打破了;导致Leader状态不能保持。
for i := 0; i < len(rf.peers); i++ {
if i == rf.me { //重大BUG:Leader不应该给自己发送心跳,一发心跳直接将Leader状态给打破了
continue
}
reply := AppendEntriesReply{}
go rf.sendAppendEntities(i, &args, &reply, successChan)
//用管道存储 成功的个数
if len(successChan) > 0 {
}
}
实验难点:
对节点状态的处理:
定时器的重置处理:
定时器stop的场景:
-
节点断开连接
-
节点成为Leader,不再需要选举超时时间的控制
定时器重置:
-
Fellow节点收到候选人投票或Leader心跳的RPC——(任期大的才改变)
-
Fellow转为Candidate的时候(选举超时)
-
Leader的心跳过时变为Fellower时