写在前面
- 本次lab2有三部分,分别是lab2A(leader选举),lab2B(记录日志),lab2C(可持续化),其中最难的点在于lab2C的
Figure 8 (unreliable)样例。 - 本次实验我是写了10天左右,尽管LAB分成了3部分,但是实际上可能由于考虑不全面通过了当前的样例在后面被测出来之后就要修改之前的代码。因此不要觉得过了样例就肯定没问题了。
- 我写的代码可以在后面给出的我的GITHUB地址去看,
本篇博客就列出我踩过坑的一部分,不分析我写的代码了。因为我打算参考GITHUB上高star代码框架进行重构再进行下一个实验。 - 通过我的通过图可以发现
Figure 8样例和Figure 8 (unreliable)样例我的rpc数量和rpc字节信息数和文档提供的通过图片比太大了。实际上最主要的原因是不知道为何我有时候无法通过Figure 8 (unreliable),而有时候就算我连续测试几十次也可以通过。我甚至怀疑我电脑坏了。再参考别人的代码自认为所有边边角角都考虑到了但是还是无济于事。因此打算参考别人代码框架进行重构。
raft lab参考资料
课程首页
课程提供的lab2文档
raft论文
常见问题guide
我的代码(github)
坑
- (必须)心跳间隔是100ms,这是课程里提到的。看知乎上有的讨论说该LAB中每秒只能调用10次RPC?
- (必须)guide里提到了心跳包并不是特别的东西,而只是一个AppendEntries RPC。
- (必须)论文中有提到选举计时器的更新时机为(1) 收到当前term或者高term的心跳包 (2) 给候选人投赞成票
- (必须)在选举成功之后,需要立刻发送心跳包。
- callRPC的调用结果有3种情况,(1)立即返回true.(2)立即返回false(3)延迟返回true或false。
- 为了降低leader选举的rpc包,本来是每次选举计时器超时开一个协程发送选举RPC请求,后来改成了当本次选举结束(同意票过半或所有人都回应)。
- (必须)在心跳阶段,必须开一个协程用来处理发送心跳,不能等到接受到所有回应才开始下一轮心跳计数。
- (必须)日志的backtrace必须进行优化,即不能按照每次nextindex每次减一这样的计算,必须按照term回退进行优化,不然如果(可能由于脑裂引起的)Log差距过大需要大量log同步的话需要一大堆
AppendEntries RPC。 - (必须)为了解决论文中figure8的情况,更新commitindex时必须确保当前对齐的位置一定是该term的,才能进行提交!!!!!
- (应该是必须)要考虑到心跳包的回复延迟接受或者延迟回复,这时对followe的log的截断处理以及leader的nextindex和mask数组的处理要特别小心。
调试方法论
貌似只能把日志写详尽然后一点一点观察了。常见的问题比如锁忘记释放似乎可以在释放锁之前打日志。
还有给最常见难以解决的问题就是不停的尝试选leader选不出来。这可能是逻辑处理的不对或者选举计时器和心跳计时器刷新的位置逻辑不对,该刷的时候不该刷的时候刷了。
不知道有没有其他好的方法可以进行调试代码。
重构
课程里要求的不要使用timer,要用time.sleep来实现,但是看知乎上以及github上的通过代码貌似都是用timer实现的,而没有使用time.sleep来实现触发选举和心跳。我打算重构一下方便之后的实验实在做不出来进行参考别人的,蒟蒻一个人肝实验太难了55555