天天看点

白话-raft协议(三)1 特殊场景-投票环节follower的赞成和拒绝2 特殊场景-candidate被“截胡”3 特殊场景-leader的提交日志4 特殊场景-同步日志5 特殊场景-作为follower被同步日志6 特殊场景-作为folloer被同步日志,发现日志不一致

1 特殊场景-投票环节follower的赞成和拒绝

在集群的每一次重新选举过程中,总会有一个节点首先成为candidate,然后向其他节点发起投票请求。这时由于各种情况,follower节点需要根据自身的当前状态选择是投赞成票还是拒绝票.vote_记录的是给谁投了赞成票

case1 小红(id=1,term=1)作为follower还没有给任何人投票(vote_=0)

  • 小红收到了小蓝(id=3)MsgVote,此时会立即给小蓝回复MsgVoteResp,并且更新自己的vote_为3

case2 小红(id=1,term=1)作为follower已经投了自己赞成票(vote_=1)

  • 这时候除了小红给自己发送MsgVote,小红会返回赞成票,其他人给小红投票都会返回拒绝票

case3 小红(id=1,term=1)作为follower给小黄(id=2)投了一个赞成票(vote_=2)

  • 这时候除了小黄给小红发送MsgVote,小红会返回赞成票,其他人给小红投票都会返回拒绝票

case4 小红(id=1,term=1)作为follower收到了某人的term=2的MsgVote

  • 上面case1到case3,假设的是投给小红的MsgVote的term都不大于小红自身的term
  • 如果小红收到的MsgVote的term大于自身term,小红也会返回赞成票,同时更新自己的vote_为发送MegVote的人

2 特殊场景-candidate被“截胡”

当小红(id=1,term=1)成为candidate后,她发送了MsgVote给其他成员等待回复,但在这时候,小红收到了小蓝(id=3)的MsgApp(要求同步日志的请求),这时候小红的反应:

  • 如果小蓝的MsgApp中的term大于等于1,小红会自动转为follower角色。把小蓝作为leader
  • 如果小蓝的MsgApp的term小于1,小红会忽略这个请求,继续等待其他成员的回复

3 特殊场景-leader的提交日志

case1 外部客户端正常发起一个MsgProp

  • 在《白话-raft协议(一)》中,小红争取到leader角色后,会发送MsgApp向小蓝和小黄同步日志,同步成功后,小红的本地日志如下:
白话-raft协议(三)1 特殊场景-投票环节follower的赞成和拒绝2 特殊场景-candidate被“截胡”3 特殊场景-leader的提交日志4 特殊场景-同步日志5 特殊场景-作为follower被同步日志6 特殊场景-作为folloer被同步日志,发现日志不一致
  • 这时客户端发送一个新的请求MsgProp(内容为“some data”),小红收到请求后,先把请求放在本地,不提交
白话-raft协议(三)1 特殊场景-投票环节follower的赞成和拒绝2 特殊场景-candidate被“截胡”3 特殊场景-leader的提交日志4 特殊场景-同步日志5 特殊场景-作为follower被同步日志6 特殊场景-作为folloer被同步日志,发现日志不一致
  • 然后小红给其他同学(小红小蓝)发送同步消息MsgApp(index=1,logterm=1,commit=1),这里小红有个变量prs_[1].match = 2,记录当前小红的日志index
  • 假设小红先收到小黄的回复MsgAppResp(index=2),小红会更新prs_[2].match = 2,这时小红会发现三个人中已有两人记录了日志index(2),会把自己的日志状态commit_设置为2,然后给小黄和小蓝发送MsgApp信息(index=2,logterm=1,commit=2)
  • 随后小红收到了小蓝的回复MsgAppResp(index=2),小红会更新prs_[3].match = 2,这时,集群大部分人(本例中是全部)日志index都等于2,小红自己的commit_也是2,小红不再继续发送请求

4 特殊场景-同步日志

白话-raft协议(三)1 特殊场景-投票环节follower的赞成和拒绝2 特殊场景-candidate被“截胡”3 特殊场景-leader的提交日志4 特殊场景-同步日志5 特殊场景-作为follower被同步日志6 特殊场景-作为folloer被同步日志,发现日志不一致

在etcd中的raft实现中,日志的存储分为两部分,一部分是storage(真正持久化的数据),一部分是unstable(内存中的数据)

  • 虚线左边的数据是持久化的数据
  • 测试用例中,小红在成为candidate前被手动设置了term为2
  • 当变为candidate时,term会自动加1,因此在unstable部分都变成了3
  • 当变为leader时,会自己追加一个空的entry

5 特殊场景-作为follower被同步日志

这里假设小红变为了follower,接收到了小黄(leader)的同步日志请求MsgApp

  • 如果小黄发送的msg中,日志索引(index)小于小红本身已提交的索引(committed),说明小红有一部分小黄不曾拥有的日志,这时的处理方式是小红直接返回MsgAppResp,把自己的提交索引(committed)告诉小黄。如果小黄发送的msg,日志索引不小于小红本身已提交的索引,那么会继续下面的检查
  • 先检查小黄msg的index,在小红日志中所属的term(任期),然后跟小黄msg中的logterm比较,不相等小红会拒绝小黄的同步日志的请求。相等继续下面的检查
  • 冲突检查,检查小黄msg中带的entries中,每一个entry里的index和term和小红本身的日志是否相同。如果都相同,返回0,如果有不想等的,返回第一个不相等的index
  • 小红根据返回的冲突的index,来判断更新自己的哪部分日志

6 特殊场景-作为folloer被同步日志,发现日志不一致

白话-raft协议(三)1 特殊场景-投票环节follower的赞成和拒绝2 特殊场景-candidate被“截胡”3 特殊场景-leader的提交日志4 特殊场景-同步日志5 特殊场景-作为follower被同步日志6 特殊场景-作为folloer被同步日志,发现日志不一致
  • 小红(follower)的日志中已经有index为1和2的日志了,小黄(leader)发给小红的Entry为(index1,term3),小红在对比时候发现,index1的term在自己日志中term是1,在小黄中,term是3,两者不一样,发生冲突。
  • 发生冲突时候,最后的日志更新以leader为主,即小红更新自己的offset为1,用小黄的Entries替换自己的unstable部分

继续阅读