【MIT 6.5840/6.824】Lab3 Raft

3A

3A的目的就是实现Leader的选举,总体来说不复杂。可分为几个部分进行实现:
首先,需要实现RequestVoteRPC,用于Candidate向其他server发起选举请求,具体实现方案论文中的Figure 2已写得很清楚了,便不再赘述。
其次,需要实现AppendEntriesRPC,用于Leader向Follower发送心跳信号(在3A中,AppendEntriesRPC只需用于发送信号),也是较为简单,不再赘述。
最后,可以利用代码给出的ticker函数,模拟Leader的心跳,以及判断Follower和Candidate是否超时,从而进行Follower变为Candidate的状态转换。当Follower转为Candidiate时,我们需要广播RequestVoteRPC发起选举,建议抽象出一个负责广播的函数,并在其中并发发送RPC,在收集到所需票数后,可在其中进行Candidate变为Leader的状态转换

3B

思路

3B对比3A,其实在思路上来看也没有很复杂,只是实现起来,需要注意的细节多了一些。
首先,进一步实现AppendEntriesRPC,支持日志同步功能。
其次,将日志同步结合进行Leader心跳之上。起初,我将心跳与日志同步分开了,搞得很复杂。但其实,它们俩都同属于AppendEntriesRPC,理应合为一体。于是,我们只需在广播心跳时,顺带把最新的日志同步至leader即可。也就是说,当用户调用Start函数时,我们不需要立刻同步日志,而是跟随心跳,每一次同步所有新添加的日志(这样做恰好可以减少所需的RPC次数)。
最后,Start函数的实现、commitIndex的更新、日志的apply都比较简单,就不赘述了。

注意点

  • 在测试的时候,我发现TestBackUp3B一直过不去,总会出现one函数fail掉的情况。经过调试发现,是同步日志的过程太慢了。因为这个测试用例中,会有很多没用的幽灵日志。当AppendEntries失败时,如果nextIndex是一步一步往后移动的话,需要很多次RPC才能够成功同步日志,所以需要采用论文中所提到的优化,每次按照一个Term去跳。(见论文第7页末到第八页首)
  • AppendEntries中,如果PrevLogIndex所指向的日志冲突了,那么需要删除自此之后的冲突条目,以防止follower提交了未同步的日志
  • Raft State中log[]的起始索引是1!!!(论文里面说的,但是写的时候容易从0开始计算索引)
  • Leader或Candidate收到RPC Reply(无论是哪种RPC)的时候,都得判断一下Reply中的Term是否比自身的更新(因为它可能断连之后重连,系统中已经有新的leader了)
  • 在apply日志时,需先把待apply的日志处理出来,然后解开锁,再发送至管道applyCh中。如果持有锁去写管道,会阻塞较久,从而影响系统中其他部分的运行,可能导致整体超时。

3C & 3D

思路

3C就不多说了,将Figure 2中提到的需要持久化的状态进行持久化即可。(为什么持久化?这个问题很简单,因为需要支持崩溃恢复,服务器crash后,内存中的状态会丢失,而不是所有的内存状态就需要持久化,故只持久化必要状态。)
3D则需要我们实现Snapshot去压缩日志。总体思路不复杂,无非是snapshot时将index偏移一下,但是实际实现上,需要修改的地方有许多(涉及到log index的地方都需要修改,建议包装成函数getRealIndex)。此外,还需要实现InstallSnapshotRPC,用于向滞后的follower同步已被压缩的日志snapshot。

注意点

  • persist的时候,如果snapshot为空,不能直接Save(raftstate, nil),而需要从persist中读取出快照,再Save
  • readPersist时,需要恢复commitIndex与lastApplied的状态,不然它们俩都会被初始化为0,从而导致一些错误
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值