本文主要是介绍6.824 Lab2 PartA实验部分,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
测试文件测试内容分析
func TestReElection2A(t *testing.T) {servers := 3cfg := make_config(t, servers, false)defer cfg.cleanup()cfg.begin("Test (2A): election after network failure")leader1 := cfg.checkOneLeader()// if the leader disconnects, a new one should be elected.cfg.disconnect(leader1)cfg.checkOneLeader()// if the old leader rejoins, that shouldn't// disturb the new leader.cfg.connect(leader1)leader2 := cfg.checkOneLeader()// if there's no quorum, no leader should// be elected.cfg.disconnect(leader2)cfg.disconnect((leader2 + 1) % servers)time.Sleep(2 * RaftElectionTimeout)cfg.checkNoLeader()// if a quorum arises, it should elect a leader.DPrintf("Check two server can choose a leader")cfg.connect((leader2 + 1) % servers)cfg.checkOneLeader()// re-join of last node shouldn't prevent leader from existing.cfg.connect(leader2)cfg.checkOneLeader()cfg.end()
}
整体测试流程如下:
1、开启3个服务器,检查能否选举出一个leader
2、一个leader掉线,看能否选出一个新的leader
3、旧的leader回归,不应该影响新的leader的状态(当然旧leader迅速被重新选举为leader也没问题)
4、下线两个服务器,此时不应该有leader
5、恢复一个机器,此时有两个机器。应该选举出一个leader
6、恢复下线机器,三台服务器同时可用,此时原有leader的状态不应该被影响
需要推敲的问题
1、断线的旧leader的回来尚未接收到发送的心跳就直接开始新的选举是否有问题
答:没问题,是运行的正常逻辑
2、lastActiveTime在哪些时候进行更新比较好?
答:应该严格遵守figure2的实现流程
If election timeout elapses without receiving AppendEntries RPC from current leader or granting vote to candidate:
只有在接收到当前leader的AppendEntries请求或者批准投票时才会对lastActiveTime进行更新
3、第五步通常会出现新来和回归的机器同时开始选举,怎么办?
答:此时第一次选举应该失败,随后因为二者的election Timeout不同,会自动开启新一轮选举得到最终结果。
4、选举的leader应该将广播时间设置比较早,以便迅速出发发送心跳的服务
核心代码示例
func (rf *Raft) startElection() {rf.mu.Lock()defer rf.mu.Unlock()now := time.Now()elapses := now.Sub(rf.lastActiveTime)// 超时的话会从Follower转为Candidateif rf.role == Follower {if elapses >= rf.electionTimeOut {rf.role = CandidateDPrintf("RaftNode [%d] changed from follower to candidate at term %d", rf.me, rf.currentTerm)}}if rf.role == Candidate && elapses >= rf.electionTimeOut {rf.lastActiveTime = nowrf.currentTerm += 1rf.votedFor = rf.merf.persist()// 准备开始发起投票,构造投票流程args := RequestVoteArgs{Term: rf.currentTerm,CandidateId: rf.me,LastLogIndex: len(rf.logs),// go不支持三元表达式,所以term赋值写在最后}lastLogTerm := 0if len(rf.logs) != 0 {lastLogTerm = rf.logs[len(rf.logs)-1].Term}args.LastLogTerm = lastLogTerm// 参数赋予流程初步结束,为了避免RPC请求停顿影响效率,先放掉锁rf.mu.Unlock()// 开始for循环不断发起响应通知进行处理cond := sync.NewCond(&rf.mu)// 初始化时全部peer里自己就已经给自己投了一票,因此初始化为1finished := 1count := 1for index, _ := range rf.peers {if index == rf.me {continue}// 发送请求并处理返回结果go func(server int, args *RequestVoteArgs) {reply := RequestVoteReply{}ok := rf.sendRequestVote(server, args, &reply)rf.mu.Lock()finished += 1DPrintf("RaftNode [%d] send Rpc to RaftNode [%d] and get response,%v,now finish %d", rf.me, server, ok, finished)if ok {// 进行逻辑运行,除了降级逻辑外,还是尽量将逻辑推迟到下面if reply.VoteGranted == true {count += 1} else {if reply.Term > rf.currentTerm {// 状态进行改变清空rf.currentTerm = reply.Termrf.role = Followerrf.votedFor = -1rf.leaderId = -1rf.persist()}}DPrintf("RaftNode [%d] get result %d,vote %d", rf.me, finished, count)}cond.Broadcast()rf.mu.Unlock()}(index, &args)}rf.mu.Lock()// 想要直接往后走:1、投票完毕 2、得到超过半数票数无需继续等待 3、已经不再是candidate状态// 注意小于等于与大于等于的使用,一开始在这里卡死便是因为小于等于直接满足for count <= len(rf.peers)/2 && finished != len(rf.peers) && rf.role == Candidate {DPrintf("finish %d,count %d", finished, count)cond.Wait()}// 不是candidate的话直接结束if rf.role != Candidate {return}DPrintf("boolean %v,count %d,total %d", count > len(rf.peers)/2, count, len(rf.peers))// 否则对状态进行判断if count > len(rf.peers)/2 {rf.role = Leaderrf.leaderId = rf.merf.lastBroadcastTime = time.Unix(0, 0) // 设置为原始时间,保证立刻发送心跳rf.persist()DPrintf("RaftNode [%d] become a leader", rf.me)}}return
}
在写的时候本人遇到的错误点如下:
1、在写逻辑表达式、if判断条件时一定要注意大于等于与大于之类的区别。
开始写成count<len(peers)/2,导致一开始直接满足条件跳过cond.wait所处的for循环,永远输出错误结果。实际上应该为count<=len(peers)/2
2、第一遍完成后遇到了split-brain问题,两个都获得了一票,总票数不等于len(peers)且没有人得票超过一半陷入死锁状态
解决方法:将rf.mu.lock从if ok块里提出来,放到rpc结果后。如果机器下线,RPC结果ok为false,也可以进行统计
编程技巧
1、尽可能使用cond.wait等方法来避免for循环空转浪费CPU资源
2、RPC调用前不要加锁,等返回结果后再加锁处理结果,以避免因为网络因素长时间无法得到结果程序无法释放出锁,影响整体执行效率
这篇关于6.824 Lab2 PartA实验部分的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!