阅读 138

Raft Part C | MIT 6.824 Lab2C Persistence

实验准备

  1. 实验代码:git://g.csail.mit.edu/6.824-golabs-2021/src/raft

  2. 如何测试:go test -run 2C -race

  3. 相关论文:Raft Extended

  4. 实验指导:6.824 Lab 2: Raft (mit.edu)

实验目标

  1. 完成persist()readPersist()函数,编码方式参照注释。

  2. 优化nextIndex[]回退方式,否则无法通过所有测试。

一些提示

  1. 测试涉及服务器故障和RPC失败等不确定事件,多次运行测试确保通过。

  2. 需要持久化的部分包括currentTermvotedForlog

  3. 有关nextIndex[]回退优化可以查看Students' Guide to Raft。

  4. 在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.TermconflictTerm

  1. 如果leader.log找不到Term为conflictTerm的日志,则下一次从follower.logconflictTerm的第一个log的位置开始同步日志。

  2. 如果leader.log找到了Term为conflictTerm的日志,则下一次从leader.logconflictTerm的最后一个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是否遗漏了某些细节。

image.png

最后,为了证明我不是在乱写,附上我的测试结果。


作者:李素晴
链接:https://juejin.cn/post/7028187143956758559


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐