6.824 Lab 记录

raft 论文(背诵全文)

Lab 2A

leader election 和 voted 不考虑日志的逻辑。应实现如下内容:

  • 初始化集群,以及两个定时器:HeartBeatTimer(stable),ElectionTimer(random).
  • 开启ticker协程,select 监听计时器事件。
  • headtbeat:leader 定时广播 AppendEntriesReq,维护集群状态,并根据Resp.Term 判断自己是否因掉线过导致版本落后,从而即使更新当前节点state。节点收到AppendEntriesReq 时 ,根据req.Term 判断是否是真的leader做出相应反应。
  • election:当前节点长时间未收到心跳,可能是leader节点挂掉等原因,当前节点进入 Candidate State, 广播 RequestVote。收到RequestVote的节点做出相应判断给予resp

需要注意几点:

  • 节点任何收到rpc请求时都应根据req.Term 更新自己以及resp的状态,从而能够让掉线过的节点及时更新state。
  • timer在随机时间时要加锁
  • 收到任何resp.Term > rf.currentTerm 时 当前节点都应变为 Follower State

Lab 2B

实现各节点间日志的复制,保证当集群中出现掉线,网络分区时各节点间的日志仍为准确,同步的。主要实现内容:

  • leader 要保证:和各节点日志的匹配状态,当广播心跳时,根据匹配状态发送相应日志,并根据返回结果,判断是否追加日志成功做出相应反应。
  • follower 要保证:根据心跳同步当前节点的日志 ,过程中要判断该leader是否过期,以及自己是否有脏日志。并且根据leader 日志的持久化index,更新自己的持久化index
  • 各节点都要保证:commit Index,apply index的同步。即可提交日志的位置和持久化日志的位置。

需要注意几点

  • commit 和 apply 的同步可以开启一个协程来监听,最暴力的方法就是sleep一段时间来检查是否可以同步了。更优雅的方法是用同步变量实现:applier 协程wait 。每当节点发现 commit 被更新时,Signal唤醒即可。
  • 广播心跳时机:1.StableTimer. 2.从client收到新日志时.3.心跳时发现follower有脏日志时,应对该节点重新发送心跳(由于这里等待心跳相应是阻塞的,所以要开启一个新协程来异步发送。这里如果是阻塞发送的话会产生集群中长时间不能选举出leader的情况,暂时没想明白为什么。。。 11.20 upd 发送心跳和处理心跳都要获得锁,这里阻塞发送死锁了。。。)
  • 由于上述广播时机有多种:那么就可能会产生leader对同一个节点发送多个相同的心跳包的情况,并且由于follower在同步日志时是覆盖同步的,所以会对这多个心跳包都回复response.Success = True。那么此时leader在更新该节点的匹配状态时如果直接将nextIndex[peer] += len(req.Entries) 的话 就会多加,导致一些列的数组越界的情况。这里的解决方法主要有两种:1.将更新匹配状态也改为覆盖更新:nextIndex[peer] = req.PreIndex + len(Entries) + 1。2. 避免对同一节点发送相同心跳包,可以额外存储一些状态,但会导致编码复杂。所以这里选择第一种。
    - 11.21 upd 在群友的帮助下:搞清楚一个东西 “leader不提交非当前term的日志” 这句话是为了保证如果当前leader泵机,新leader又没有这条非当前term的日志的时候。新leader覆盖了这条“被提交日志”的case,所以这里应该有一个前提条件就是leader在当前term内没有向大多数Peer 同步过日志。原因很显然:如果leader向大多数peer同步过了日志,那么新的leader一定会有这条非当前term的日志了,也就不会出现覆盖的情况。对应代码上:在找大多数节点的matchIndex时不考虑那些最后一条日志的term!=rf.term 的情况

这里可以额外总结一下 日志从client发到leader ,到同步到follower的基本流程:

  1. client 向 leader 发送command
  2. leader 同步到自己的log中
  3. leader 向各个节点发送心跳包。
  4. 各节点收到心跳包并同步到他们自己的log中
  5. 返回同步结果
  6. leader根据同步结果,更新各节点的日志状态(match, next),以及自己的commitIndex
  7. 根据commitIndex 更新applyIndex持久化。
  8. 等待下一次client的command

可以看到如果上述的流程完全顺序执行的话,效率是十分低下的。
所以需要对一部分进行异步的优化:
1.client 向leader发送command
2.leader同步到自己的log中
3.异步发送心跳包。继续接受client的command
4.处理response时,发现commit被更新了,唤醒持久化applier的协程,并将结果返回给客户端。

(打了好几天游戏,进度有点慢了,接下来记录一下每个lab的时间)

Lab 2C (11.18~11.20)

11.18 又玩了一天游戏 咕咕咕
11.19 打游戏了,鸽
11.20 Complete

持久化一些信息,用于重启某个机器时恢复信息,用官方提供的接口就可以,不理解为什么要单独放一个lab

想过所有test的话这里要 对处理日志冲突的case做一些优化:发现冲突时不能简单的将nextIndex - 1 这点论文也提到了。

。。其他的没什么要注意的地方。。。
今天就到这里QAQ,明天继续

  • 11.22 upd 在lab2C测试中发现有一种case也会导致多个peer在某个idx 的apply不一致的情况,case:leader对某一个peer发送一个长log 心跳和一个短log心跳,长log先到后follower返回心跳成功,leader 更新matchIndex=k导致更新commitIndex=k进而更新apply,此时如果短log到,那么就会导致follower的log回退的情况,因此该节点就有可能成为新的leader导致但是却没有已经apply的log的情况

Lab 2D (11.21~)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值