mit_6.824_2021_lab2C_persistence

mit_6.824_2021_lab2C_persistence

persistence 引入持久化,持久化的相关代码已经在 persister.go 中实现,我们要做的只是调用 api 就好,相对容易的一节;

但同时也是不容易的一节,因为这一节中有两个关于 图8 的网络崩溃节点崩溃实验,基本都会出 bug,出 bug 基本都是因为 lab2A 和 lab2B 引入的 bug;

本人也因为 lab2B 引入的 bug 导致在 lab2C 卡了很久;这里阐述一下自己的心路历程

lab2C_persistence

实验内容

  1. 在 raft.go 中实现 persist()readPersist(),需要将状态编码为字节数组,并调用Persister 的api;参阅persist()readPersist() 中的注释即可,且在 go 中不要使用小写字段名称对结构进行编码,否则会错误
  2. 在对论文图2中需要持久化的状态更改时调用persist()

实验提示

  • 建议使用 go-test-many.sh 脚本多测几次,有时候 pass 只是偶然
  • 实现 nextIndex 优化,可以参考助教的 guide
  • 虽然 2C 只要求实现持久性和快速日志回溯,但 2C 测试失败可能与之前的实现部分有关。即使你通过了 2A 和 2B,但是 2C 也可能会失败

实验思路

持久化

论文图2已经很清楚地说明了什么数据需要持久化,我这里的实现是设置一个 setter 做行为拦截,最后都需要调用persist(),在需要修改这些属性的地方统一调用的是 setter 而不是直接更改,这样持久化就不会入侵主流程逻辑了;(更新:这个不可取)

并且对 log[]封装 setter 很有必要,lab2D 快照的引入会导致日志条目的下标逻辑需要改造

nextIndex 优化

需要改造AppendEntries以及其请求体和返回体,添加ConflictIndexConflictTerm字段

需要阅读助教的 guide,其中有一段原文为:

  • If a follower does not have prevLogIndex in its log, it should return with conflictIndex = len(log) and conflictTerm = None.
  • If a follower does have prevLogIndex in its log, but the term does not match, it should return conflictTerm = log[prevLogIndex].Term, and then search its log for the first index whose entry has term equal to conflictTerm.
  • Upon receiving a conflict response, the leader should first search its log for conflictTerm. If it finds an entry in its log with that term, it should set nextIndex to be the one beyond the index of the last entry in that term in its log.
  • If it does not find an entry with that term, it should set nextIndex = conflictIndex.

建议直接读英文版,先按逻辑自己实现一次

已经说明地很清楚了,只要照做就能实现,只是这里不理解为什么,梳理之后,逻辑如下:

  • 若 follower 没有 prevLogIndex 处的日志,则直接置 conflictIndex = len(log)conflictTerm = None
    • leader 收到返回体后,肯定找不到对应的 term,则设置nextIndex = conflictIndex
    • 其实就是 leader 对应的 nextIndex 直接回退到该 follower 的日志条目末尾处,因为 prevLogIndex 超前了
  • 若 follower 有 prevLogIndex 处的日志,但是 term 不匹配;则设置 conlictTerm为 prevLogIndex 处的 term,且肯定可以找到日志中该 term出现的第一个日志条目的下标,并置conflictIndex = firstIndexWithTerm
    • leader 收到返回体后,有可能找不到对应的 term,即 leader 和 follower 在conflictIndex处以及之后的日志都有冲突,都不能要了,直接置nextIndex = conflictIndex
    • 若找到了对应的term,则找到对应term出现的最后一个日志条目的下一个日志条目,即置nextIndex = lastIndexWithTerm+1;这里其实是默认了若 leader 和 follower 同时拥有该 term 的日志,则不会有冲突,直接取下一个 term 作为日志发起就好,是源自于 5.4 safety 的安全性保证

如果还有冲突,leader 和 follower 会一直根据以上规则回溯 nextIndex

引入的 bugs
  1. 晦涩难懂的代码:在写日志强制覆盖写的时候,写了一段以下标变换的自以为很秀的代码,结果就是晦涩难懂,最后重构成简单易懂的分类讨论
  2. nextIndex 优化:在找 nextIndex 优化的指定下标时,默认了 term 连续,这里 term 很可能不是连续的,有可能会找不到
  3. 正确处理 rpc 请求:在 发送 rpc 请求 和 处理 rpc 返回体时都需要判断一次自身状态,即currentTermstate;举个例子,本人遇到的 bug 是,一个陈旧的 leader 在广播后,接收到第一个 follower 的 reply,其 term 是比自身的 term 要大的,陈旧 leader 变回 follower,并且 term 更新,但是因为仍在广播,在发送第二个 rpc 请求时,若没有检查自身状态,则会以 follower 的身份将错误的 log 发送给其他 follower,导致 apply error

感想

讲道理,lab2C 的内容其实算是很少的了,但是本人因为 lab2B 引入的bug,导致 lab2C 卡住的时间是最久的;真的,要设计封装好代码,不要写晦涩难懂的,然后遇到 bug 只能多打日志,在上千行日志里找逻辑错误

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值