Raft Part C | MIT 6.824 Lab2C Persistence
实验准备
实验代码:
git://g.csail.mit.edu/6.824-golabs-2021/src/raft
如何测试:
go test -run 2C -race
相关论文:Raft Extended
实验指导:6.824 Lab 2: Raft (mit.edu)
实验目标
完成
persist()
和readPersist()
函数,编码方式参照注释。优化
nextIndex[]
回退方式,否则无法通过所有测试。
一些提示
测试涉及服务器故障和RPC失败等不确定事件,多次运行测试确保通过。
需要持久化的部分包括
currentTerm
、votedFor
、log
。有关
nextIndex[]
回退优化可以查看Students' Guide to Raft。在Lab2A和Lab2B中测试未能发现的错误可能会在Lab2C中暴露出来。
持久化
这部分其实很简单,代码中的注释已经很清晰了,当然你要注意data race问题。
func (rf *Raft) persist() { w := new(bytes.Buffer) e := labgob.NewEncoder(w) e.Encode(rf.currentTerm) e.Encode(rf.votedFor) e.Encode(rf.log) rf.persister.SaveRaftState(w.Bytes()) } func (rf *Raft) readPersist(data []byte) { if data == nil || len(data) < 1 { return } r := bytes.NewBuffer(data) d := labgob.NewDecoder(r) d.Decode(&rf.currentTerm) d.Decode(&rf.votedFor) d.Decode(&rf.log) } 复制代码
nextIndex优化
Part B中对于失败的AppendEntries请求,让nextIndex自减,这样效率是比较慢的。
优化点1
如果follower.log
不存在prevLog
,让Leader下一次从follower.log
的末尾开始同步日志。
优化点2
如果是因为prevLog.Term
不匹配,记follower.prevLog.Term
为conflictTerm
。
如果
leader.log
找不到Term为conflictTerm
的日志,则下一次从follower.log
中conflictTerm
的第一个log的位置开始同步日志。如果
leader.log
找到了Term为conflictTerm
的日志,则下一次从leader.log
中conflictTerm
的最后一个log的下一个位置开始同步日志。
nextIndex
的正确位置可能依旧需要多次RPC才能找到,改进的流程只是加快了找到正确nextIndex
的速度。
AppendEntries中有逻辑如下。
reply.Term = rf.currentTerm reply.Success = false if len(rf.log) <= args.PrevLogIndex { reply.ConflictIndex = len(rf.log) reply.ConflictTerm = -1 return } if rf.log[args.PrevLogIndex].Term != args.PrevLogTerm { reply.ConflictTerm = rf.log[args.PrevLogIndex].Term for i := 1; i <= args.PrevLogIndex; i++ { if rf.log[i].Term == reply.ConflictTerm { reply.ConflictIndex = i return } } } 复制代码
Heartbeat中有逻辑如下。
if !reply.Success { if reply.ConflictTerm == -1 { rf.nextIndex[id] = reply.ConflictIndex } else { conflictIndex := -1 for i := args.PrevLogIndex; i > 0; i-- { if rf.log[i].Term == reply.ConflictTerm { conflictIndex = i break } } if conflictIndex != -1 { rf.nextIndex[id] = conflictIndex + 1 } else { rf.nextIndex[id] = reply.ConflictIndex } } } 复制代码
实验总结
Part C并不算是Raft算法的核心部分,关于nextIndex的优化本文是参照了Students' Guide中的方式。
如果你完成了持久化和回退优化两个部分依然无法通过所有测试,那可能要仔细的检查Part A和Part B是否遗漏了某些细节。
最后,为了证明我不是在乱写,附上我的测试结果。
作者:李素晴
链接:https://juejin.cn/post/7028187143956758559