白话-raft协议(一)

前言

下面文章会以图形方式来解读raft协议,与其他作者文档相比,会更偏向工程的实现细节

适合读者:

  • 想了解raft协议的懒人,不想读论文,不想看代码,不想动脑袋。。。

对一般人而言,了解raft协议,https://raft.github.io/这个网站都会接触到,它提供了:

动画部分建议先了解下,有助于下面的学习。

下面的raft流程交互和参数说明参考了etcd中的raft实现

1 初识

19世纪80年代,小红(id=1)、小黄(id=2)、小蓝(id=3)三位同学商量放假去哪儿玩,她们之间商议过程只能通过书信(会发生各种意外情况导致信件丢失或者回复缓慢)。我们一起看看三人之间是如何达成一致意见的。

先熟悉第一个概念,角色。每位同学都会分属下面三种角色之一:

角色 英文
领导者 leader
跟随者 follower
候选者 candidate

故事开头,每个同学都是follower角色

2 领导者选举

2.1 选举超时时间 election timeout和任期term

既然是商量事情,总有一个要先提意见的,为了公平起见,给每位同学一个随机的超时时间(election timeout),谁先过了超时时间就准备开始发言

白话-raft协议(一)

图中,小红150mm时间最短,小红最先超时

与超时时间类似,每位同学都有一个任期属性,正常情况下每发起一次选举,任期会自动加1,初始状态大家的任期都是0,图中的其他属性暂时忽略

2.2 小红的自我投票(MsgHup)和投票请求(MsgVote)

2.1节中小红最先到达超时时间,她的动作如下所示:

白话-raft协议(一)

  1. 小红首先给自己发了一个Message1,type为MsgHup,告知自己要参与选举了
  2. 小红收到Message1后,将自己的term由0改为1,状态由StateFollower改为了StateCandidate,至此角色由follower转换为了candidate,顺便给自己投了一票(votes[1]=ture)
  3. 小红在term为1的任期内正式向小黄和小蓝发起投票请求(Message2.1和Message2.2) ,type为MsgVote

2.3 小黄和小蓝的回复(MsgVoteResp)

先看小黄的回复:

白话-raft协议(一)

  1. 小黄接收到Message2.1后,将Message2.1的term(1)与自身的term(虚线框0)比较,发现自身的term小于Message2.1,继续保持自己的follower角色,同时将自身的term改为1
  2. 小黄向小红发送Message3.1进行回复,type为MsgVoteResp

小蓝的回复与小黄类似,回复Message3.2,见下图,不再赘述:

白话-raft协议(一)

2.4 小红变为了leader

白话-raft协议(一)

  1. 小红先收到了小黄的Message3.1,type为MsgVoteResp。这时候小红已经获得了两票,一票是自己投自己,一票是小黄投的(对应图中的votes[i]变量,votes[1]=ture,votes[2]=true),小红得票已经超过集群的半数,由此小红的状态从StateCadidate转变为了StateLeader
  2. 接着小红给自己创建了一个空日志条目,开始向小黄和小蓝发送Message4.1和Message4.2,type为MsgApp,即要求follower同步自己的数据
  3. 小红的prs[1].match_=1

小红收到了小黄的Message3.1后,由于满足半数投票,已经变为了leader角色,这时再收到小蓝的Message3.2,不再需要做任何操作

这时,小红在本地记录了一个空的Entry

白话-raft协议(一)

  • 此时的Entry只是临时记录,所以为虚线

3日志同步

3.1 小黄和小蓝的回应MsgAppResp

2.4节小红开始向小黄和小蓝发送Message4.1和Message4.2,下面是小黄和小蓝收到后的回复

白话-raft协议(一)

  • 小黄和小蓝收到信息后,各自也准备了一个空的Entry,并且向小红回复了type为MsgAppResp的Mesaage(Message5.1和Message5.2)

此时,三位同学的日志状态如下:

白话-raft协议(一)

3.2 小红确认日志记录,继续发送MsgApp

白话-raft协议(一)

  • 小红收到小黄的Message5.1后,会设置prs[2].match_=1,至此已经有半数以上(2个人)同意进行日志提交,因此小红将自身的raftLog.committed_由0设置为1
  • 小红处理完Message5.1后,会继续向小黄发送Message6.1,type为MsgApp,继续同步日志记录。与Message4.1不同的是,此时index、logterm、commit由0变为了1
  • 小红继续受到小蓝的Message5.2,会设置prs[3].match_=1,处理完后同样会发送Message6.2给小蓝,index、logterm、commit同样为1

此时日志状态,小红的日志由虚线变为实线

白话-raft协议(一)

3.3 小黄和小蓝确认日志记录

白话-raft协议(一)

  1. 小黄收到小红Message6.1后,根据msg中的commit为1,修改自己的commit为1,然后发送type为MsgAppResp的Message7.1
  2. 同理,小蓝也会修改自己的commit为1,然后返回type为MsgAppResp的Message7.2

此时日志状态,小蓝和小黄由虚线变为实线

白话-raft协议(一)

3.4 小红的收尾

  1. 当小红收到Message7.1后,检查msg中的index和本地的prs[2].match_,两者相等,不做任何操作
  2. 同理,小红收到Message7.2后,检查msg中的index和本地的prs[3].match_,两者相等,不做任何操作
上一篇:DDD如何设计落地?(库存,产品账示例)


下一篇:达摩院的MindOpt优化求解器发布新功能,又获第一,还免费