mit6.824 lab2 RAFT log Replication 要点记录

我的6.824 课程 Pass,欢迎STAR

主要任务: 完成keep a consistent replicated log of operation

  • election restriction: 也就是大多数机制,通过大多数机制阻止没有获得上一个commitLog的node的选举。
  • 时间上的建议:real time 不超过1min,cpu time 不超过5s
  • 对于log的commit:通过对rf.matchIndex进行排序,取len(rf.peers)/2索引处将要commit的log
  • 实现的log replication的时候,考虑到测试中command的命令都很短,不在关键路径上面,在node收到AE时没有进行preLogInd和preLogTerm的比较,而是直接进行replace,如果command比较大或者说操作比较耗时,就需要比较然后replace
  • 这里AE在被reject以后,是存在回滚的机制:返回到没有conflict的那一个阶段的
    • easy way: leader 对被reject的AE依次递减在发出直到leader中的记录的follower状态与follower相同步,然后在对那个一致的状态节点开始。
    • optimized way: follower 返回不一致节点的Term信息,以使leader跳过那个term,同时leader在初始时设置一个term的最后一个index的缓存,这样方便在进行log backup 的时候快速查找。
    • 这里有一个实现上的问题,leader在繁忙时一个请求接一个请求的时候,如果follower的状态发生比较大的不一致,这时会进行会滚。这时会滚的操作是耗时的,下一个请求再来(slow node 不影响请求的处理),会新开另外一个go routine,也同样会进行会滚,前一个goroutine 会快一些,最终会趋于一致,但是如果会滚的速度没有请求过来处理的速度快,可能会造成goroutine不断的增加。这个过程同样会因为导致一些数据同步的问题
  • 一直没有注意,make传过来的applyCh 是用来进行验证的,成功的消息要发送到这个通道里面才能被config进行了解并验证,所以在每一个RAFT节点内部都内置一个channel,把传进来的applyCh赋给该内置channel。 这样当消息commit以后就把applyMsg发送到那个channel中去(这样需要考虑persist以后readpersist时的channel关闭的问题)
  • 当leader收不到其他的消息时而超时时,应该关闭其所产生的AE分发的goroutine(通过指定的尝试次数,尝试了一定时间以后就选择结束goroutine或者通过在RPC调用前面判断自己是不是leader,不是就退出过程)
  • 对于Leadercommit的更新应该在HB和AE分发的过程中都有,这就要求在HB的entries判断为空并返回之前进行。(设置如果prevlogindex和prevlogterm都匹配,就一直commit到最新的commitIndex的位置):。为了避免一次commit 出错,这次的添加数据需要由下一次(更新leaderCommit以后)的HB或者AE进行更新
  • leader对于command,应该是马上就附加到log上的,之前是在完全commit以后才进行的,哇,蛮多的东西要改,因为直接加在末尾的话,是可以不需要那个Raft中未执行command的channel的。
  • 原来的Raft定义的commandTerm是小写的,不能够被外部所访问,改成大写的方便访问。
  • follower应该对HB/AE中的leaderCommit进行判断,并且适时的commit自己的logs
  • 对于卡着一直不能被commit的命令,后面的命令也能来进行AE,但是LeaderCommit没办法向后更新。
  • 在leader和candidate函数中,如果因为收到更高的leader的消息然后退出,那么所有的goroutine也会因为自己不是leader而推出。
  • 并发导致的问题:对于node,rpc调用和 node主要执行函数(leaderProcess)及goroutine是同步进行的,这样在rpc中修改的东西,可能会立刻反应在goroutine中导致程序失败。还有node主要执行函数需要在关键的操作之前如AE分发,判断当前的身份,避免已经不是leader了,还在执行leader的动作。
  • 这个过程中的并发操作是真的不好操作,多数情况下,AE和RV的分发程序,以及AE和RV的响应RPC,有些操作是不需要特别的加锁的(取到旧值不影响操作),有些是需要加锁避免出错,特别是在Log replication的过程中。
  • 并发操作的过程中,由于调度器的调度,AE_RPC可能出现prevLogIndex已经被commit过的情况,这时在AER为false时应该在leader中进行判断。
  • 在leader被隔离的时候,可能会收到别的命令但是无法commit,当leader恢复以后,自身的命令更长,但term小,所以无法被选举,而如果该leader的ElectionTimeout 也比较小,更容易变到下一个term,这个时候,就可能进入一个死锁的状态,该leader先进入下个term并进行RV,其他的node不会vote this leader,但是会update term and go to follower,leader 么有收到vote,首先进入超时,并重启下一次的选举。term又比其他人的大,但是同样不会得到vote,就这样死循环。 解决办法:在RV_RPC中,当term相等并且当前自己是candidate的时候,如果对方的更新(如下),则vote true and turn to follower

If the logs have last entries with different terms, then the log with the later term is more up-to-date. If the logs end with the same term, then whichever log is longer is more up-to-date.

  • 在testRejoin2B中,出现了恢复的节点的electionTimeout过小,由于本身缺失了一部分的log,所以在RV_RPC中无法获得vote,(同上一个描述), 可以采用与论文中描述的不一致的方法:在RV收到的term比自己的大的时候,不是任何时候都去变成follower,只有在voting true的时候才更新。这也是我采用的方法,完美破解这种锁情况
  • 之前没有做好Kill的善后操作导致在开始下一个 test的时候会出现问题。可以在kill被调用的时候,设置leaderNum为-1,并且阻塞主routine mainProcess的执行(我这里阻塞了很久,足够之后的Test都执行完)
  • 说真的,并发程序真的不好写,一不小心就漏掉了同步
  • 因为并发的存在,在对raft node本身的属性进行修改时,比如commitIndex赋为a,需要先判断commitIndex是否比a更大,如果更大就不更新,注意:判断的过程也应该在锁作用域里
  • raft中命令执行是串行的,前面没有commit,后面也不能commit。前面的如果不commit那么说明没有得到超过半数的同意
Other problems
  • leader在主动退让以后,follower会等待最后的一个electionTimeout结束,leader已经开始了下一轮的election,这样会使follower在竞争中处于不利地位,一直无法获取到leader身份,同时leader也可能由于大量的工作而宕机
  • 有个细节:RV_RPC和AE_RPC两个对term的修改是否需要对相应的计时器进行修改。

LAB2 的task1 leaderElection
LAB2 的task3 node persist

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值