Lab2B
TODO
官方动画 https://raft.github.io/raftscope/index.html
-
完成TestBasicAgree2B测试,实现Start()函数,编写AppendEntries代码实现log entry的发送和接收,通过applyCh发送和接收log entry.
-
实现election restriction,论文的5.4.1章节.
-
测试未达成协议的方法可以用重复选举,即使leader还正常工作.找到选举定时器或选举成功不发送心跳的bug.
-
重复循环要加入sleep.
-
帮未来的自己一个忙,保持代码整洁.
-
如果测试失败了,看一下config和test的代码,了解测试流程.
测试案例
TestBasicAgree2B
- 调用start前不应该有peer接收到log
- 遍历所有peers,如果有leader,调用start函数
- 如果调用成功,测试是否所有peer收到正确log
记得提交log同时通过applych发送log
TestRPCBytes2B
校验RPC发送的字节数,确保每个log只对peer发送一次,发送10条log,校验log command字节总数与抓包捕获的字节总数是否一致.
For2023TestFollowerFailure2B
校验Follow丢失连接之后是否正常工作
For2023TestLeaderFailure2B
校验Leader丢失连接之后是否正常工作
- 发送一条log
- 断开leader连接,剩下两个peer选出一个leader,再发送两条log
- 断开leader连接,现在客户端只能连接一个peer
- 遍历peer调用start() 测试是否有peer提交了日志
之前leader向follow同步日志成功修改matchindex时加上同步日志的数量,在leader重新选举后matchindex列表会初始化为0,需要改为nextindex - 1
rf.nextIndex[server] += len(args.Entries)
rf.matchIndex[server] += len(args.Entries)
rf.matchIndex[server] = rf.nextIndex[server] - 1
TestFailAgree2B
校验follow断开连接后发送4条log,之后重连,再发送两条日志,是否正常工作
func TestFailAgree2B(t *testing.T) {
servers := 3
cfg := make_config(t, servers, false, false)
defer cfg.cleanup()
cfg.begin("Test (2B): agreement after follower reconnects")
cfg.one(101, servers, false)
// client发送msg:101,leader:S1收到并同步到S0 S2
leader := cfg.checkOneLeader()
cfg.disconnect((leader + 1) % servers)
cfg.one(102, servers-1, false)
cfg.one(103, servers-1, false)
time.Sleep(RaftElectionTimeout)
// 此时disconnect 的 follow会timeout并开始选举 但是拿不到选票只会自增term 为2
cfg.one(104, servers-1, false)
cfg.one(105, servers-1, false)
// leader接收到 102 103 104 105 并同步到正常的follow
// 恢复连接 此时leader发送的appendrpc的reply term会大于leader term 把自己置为follow 超时开始选举
PrettyDebug(dTrace, "S%d re connect TestFailAgree2B ", (leader+1)%servers)
cfg.connect((leader + 1) % servers)
// the full set of servers should preserve
// previous agreements, and be able to agree
// on new commands.
cfg.one(106, servers, true)
// 选举成功此时term=3,但是106提交的日志是term2提交的,所以106日志不会提交到状态机
time.Sleep(RaftElectionTimeout)
cfg.one(107, servers, true)
cfg.end()
}
还有个问题是106log到来的时候是term1写入的,然后重新选举到了term3,这时候由于106log的term与current term不一致,所以不会提交
// 原来更新commitindex是从小到大更新,要改为从最新的index从大到小更新
N := rf.commitIndex + 1
count := 1
for server := range rf.peers {
if server == rf.me {
continue
}
if rf.matchIndex[server] >= N {
count++
}
if count > len(rf.peers)/2 {
PrettyDebug(dLog, "S%d,updateCommitIndex server:%d,count:%d,rf.log[N].Term:%d,rf.currentTerm:%d",
rf.me, server, count, rf.log[N].Term, rf.currentTerm)
}
if count > len(rf.peers)/2 && int64(rf.log[N].Term) == rf.currentTerm {
PrettyDebug(dLog, "S%d,updateCommitIndex rf.commitIndex++",
rf.me, rf.commitIndex)
rf.commitIndex++
break
}
}
TestFailNoAgree2B
5个peers,断连3个后重连,测试是否正常
TERM 1: 5个peer都写入 msg 10
S2 S3 S4 断线 超时
S1 写入 msg 20 index 2
转TERM 2 开始选举 恢复连接
S3 成为 TERM 3的 leader
写入msg 30 msg 1000
这时候S1的log index=2 为msg20,prelog 1 的index和term都匹配,直接把msg 30 1000插入了,应该要把msg20删除的
TestConcurrentStarts2B
处理并发Start()写入
TestRejoin2B
- 写入msg 101 leader1断开连接
- leader1写入102 103 104
- leader2写入103 然后断开连接
- leader1重连
- 请求写入104
- leader2重连
- 写入105
当server 0 重新上线之后与仅存的一个peer日志不同,永远选不出leader来,这里是被翻译版的fig2坑了,后来查原文说的是 at least as up-to-date,至少不晚于
修改逻辑为:
- 如果 term 不同,那 term 新的那个 log 胜出;
- 如果 term 相同,那 index 更大(即更长)的那个 log 胜出。
在第6步leader2重连之后会同时存在两个leader,当leader1发送logapppend给leader2,leader2同时发送logapppend给leader1,leader2发送之前要解锁,这一瞬间收到了leader1的log,发现term比自己大,转为follow,并且同步log,这时候sendappendlog的rpc args就会data race,这一步卡了很久.后来发现是appendargs构建日志的时候要深拷贝.
TestBackup2B
在少部分节点失效,多部分节点失效环境下,尽快完成两百个命令的正确处理.
随机提交msg,然后3个follow 2 3 4断开,向leader1 2提交50个msg,然后剩下两个节点也断开,2 3 4重连,向新集群
提交50个msg,断开现在的一个follow,给现在的leader发送50个msg,断开所有节点,重连3个节点,提交50个msg,重连所有节点,然后提交1个msg,不能出错
当全部节点丢失链接然后1 3 4节点连接后,3号和4号节点一直自增竞选,1号节点接收到投票请求后重置了选举时间,所以一直不发起选举,而3 4节点的日志落后一直拿不到1号节点的选票.
TestCount2B
检查无效通信的次数,这个没有出问题
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通