过家家巧说raft算法

目录

一 一致性

二 Raft算法

1 leader选举

2 日志复制

3 leader切换时如何保证日志完整性

三 参考文献


一 一致性

       一致性是指分布式系统中的多个服务节点,给定一系列操作,在特定协议的保障下,使这些节点对外呈现的状态是一致的,即保证集群中所有服务节点中的数据完全相同并且能够对某个提案达成一致,为什么需要一致性?
1 数据不能存在单个节点(主机)上,否则可能出现单点故障。
2 多个节点(主机)需要保证具有相同的数据。
3 一致性算法就是为了解决上面两个问题。

二 Raft算法

        Raft是实现分布式共识的一种算法,主要用来管理日志复制的一致性。它和Paxos的功能是一样,但是相比于Paxos,Raft算法更容易理解、也更容易应用到实际的系统当中。下面用小时候经常玩的过家家来解释raft算法的工作原理,首先会有以下游戏规则,对应raft算法中的一些具体实现规则:
     C1 游戏中,每个小孩子都想做一家之主(谁不想当爸爸呢,叫爸爸),每个人发现当前没有人做爸爸就会主动申请做爸爸,发起投票
     C2 每个人看到有人发起投票时,如果发起人的请求合法就会投赞成票(实际的投票规则会更复杂,这里先做简单假设),当赞成票超过所有成员数的一半时,申请人成功当选爸爸
     C3 爸爸是有任期的,每发起一次投票任期就会累计
     C4 游戏中有三种身份:一家之主爸爸(leader),家庭成员(follower),独立状态(Candidate)(家庭纠纷吵架了,六亲不认这时候需要重新选取新的家长)
     C5 小孩子记性不好,小孩子的记忆在2s-5s之间(选举计时器election timeout 一般设置为 150ms~300ms 之间的随机数),所以一家之主需要不停的告诉其他成员自己是家长(实际上就是leader和follower的心跳),如果家庭成员忘记了谁是爸爸(选举计时器)超时,就会发起新的选举(所以实现中心跳的时间一定要比选举定时器短)。
     C6 游戏中只能有一个爸爸,没有干爸也没有隔壁老王,其他都是家庭成员
     C7 爸爸负责家庭所有的事务处理,成员只负责记笔记(写日志),当爸爸收到事务请求时自己记笔记的同时会广播给成员,成员收到通知自己记录后会给爸爸相应,如果爸爸收到超过一半的相应,则爸爸会则爸爸或通过此事务(commited)
     C8 家庭成员不处理任何外部事务,只处理leader的消息或者投票请求,如果收到外部事务请求会转给爸爸处理
     C9 如果家庭成员在一定的时间内没有收到爸爸自己是爸爸的证明通知(见C5),则家庭成员会认为你不想干了,就会发起新一期的选举,竞选新一期的爸爸
     C10 当某个家庭成员接收到爸爸的证明通知所携带的任期号大于当前节点本身记录的任期号,那么该节点会更新自身记录的任期号,同时会切换为Follower状态并重置远举计时器

1 leader选举

     游戏开始时大家默认都是成员的身份,一段时间后,假如成员a先发现一段时间内没有收到爸爸自己是爸爸的证明通知(见C5)了,就会发起当爸爸的请求(切换为Candidate状态)任期为1,其他成员收到投票请求后拿出笔记本一看自己的任期数都是0,都没有投出任期为1的票,所以立马投赞成票(见C2)。当节点a收到超过一半的赞成票后就会在当前任期中切换成爸爸节点,其他节点为成员节点,同时所有的节点都会累加自己任期值。

     这里有一种特殊情况,假如2个家庭成员a和b同时发现没有收到爸爸的任职通知,这时候就会同时发起选举,这个时候两个选举请求会分别先后到达其他节点,其他节点第一次该任期收到选举请求投出同意后会累加本地的任期数,当第二个投票请求到来是发现投票请求中携带的任期数已经投过了就会投出拒绝票,此时会出现三种情况
1 a得到超过一半的赞成票而b少于一半,此时a选举成功
2 b得到超过一半的赞成票而a少于一半,此时b选举成功
3 a和b都为获得超过一半的选票,则该任期选举失败,等待下一个成员的选举计时器超时,开启下一任期的选举
     不过这种情况发生的几率并不高,因为提到过 election timeout 是在一个时间区间内取的随机数,并不是一个固定的值(见C5)
     接下来看一下leader节点宕机的情况,假如当前当家长的小孩子A被一个玩具或者一个零食吸引了走了,不干正事了脱离游戏了,此时其他的家庭成员就不会收到来自爸爸的证明通知,那么就会有一个成员B发现有人叛逃了,就会立马发起新以任期的选举请求(见C1),其他成员收到投票请求后拿出笔记本一看选举任期大于当前投出的任期数就会投出赞成票(见C2),此时B就会成为新一任期的爸爸,继续当家做主。当小孩A开小差又想回来玩的时候,会收到节点B是爸爸的通知,该通知中携带的任期号大于节点 A 当前记录的任期号,所以节点 A 会切换成 Follower 状态(见C10)。

     最后来看一下由于网络故障导致网络分区的情况,游戏过程中,一群小孩子拉帮结派,只想跟自己想玩的人玩游戏,于是就出现了两个小团体。

     当出现这种情况时,成员A的心跳消息只有节点B能收到,而集群中的其他节点收不到,假设分区之前A是爸爸,一段时间过后,组成新团体的C,D和E中会有一个节点发起选举(见C9),这里假设该节点是E,在新团体中只有节点 C、 D 都会投赞成票,加上E自己的一票超过半数,E就会成为新团体中的爸爸,而此时A是另外一个团体中的爸爸,但是E的任期数比A要大。

   

    当网络故障被修复时会如何呢,加入拉帮结派的小朋友玩了一段时间后被老师发现了,一顿批评后重归于好,此时网络分区也就会消失,此时爸爸A发送的爸爸证明会被重新节点 C、 D 、 E 接收到,但是这些心跳消息中携带的 Term 值小于当前 C、 D 、 E 节点的Term 值,会被 C 、 D 、 E 节点忽略:同时,爸爸E发送的心跳消息会被节点 A、 B 接收到,A和B收到
比自己笔记本里记录的任期大的爸爸证明后发现有新爸爸了就会自动切换为家庭成员(follower),因为同一游戏中只能有一个爸爸(见C6)
    这里会有一种特殊情况加入游戏过程中出现了严重的拉帮结派,出现了很多个小团体小组织,导致很多小团体的成员数不足半数,此时这些小组织会出现无法选举出新的爸爸。待一段时间之后,会再次发起新一轮的选举,循环往复,从而导致不断发起选举, Term 号不断增长,直至溢出。在 Raft 协议中对这种情况有一个优化,当某个节点要发起选举之前,需要先进入一个叫作PreVote 的状态,在该状态下,节点会先尝试连接集群中的其他节点,如果能够成功连接到半数以上的节点,才能真正发起新一轮的选举。

2 日志复制

      爸爸节点会将将客户端的更新操作以打包成消息(Msg1)发送到集群中所有的成员节点。当成员节点的小本本记下收到的这些消息之后,会向爸爸节点返回相应的响应消息(Msg2)。当爸爸节点在收到半数以上的成员节点的响应消息之后,会对客户端的请求进行应答,接着爸爸节点会提交客户端的更新操作,该过程会再次发送消息(Msg3)到成员节点,通知成员节点该操作己经提交,同时爸爸节点和成员节点也就可以将该操作应用到自己的状态机中。
    每个节点为了保证日志的完整性,小本本上会维护commitlndex和lastApplied 两个值,commitlndex表示的是当前节点接收到爸爸节点已提交通知的日志的最大索引也就是接收到Msg3
通知的最大日志索引,更新commitlndex后本节点就会把对应的日志引用到自己的状态机中,而lastApplied就记录了当前节点应用到自己状态机中最大的索引日志。因此当节点中的
commitlndex值大于lastApplied 值时,会将lastApplied 对应的日志应用到其状态机中并lastApplied加l。
    作为一家之主的爸爸,需要牢记家庭成员的状况,维护nextlndex和matchlndex两个数组,其中nextlndex数组记录了需要发送给每个家庭成员节点的下一条日志的索引值,matchlndex
记录了己经复制给每个家庭成员节点的最大的日志索引值。爸爸节点会发送从nextlndex开始的所有日志到对应的成员和节点,如果对应成员节点返回成功响应,则更新相应该 Follower 节点对应的nextlndex 值和 matchlndex值,如果因为日志不一致返回失败消息,则减少 nextlndex 值重试,直到返回成功为止,如此一来保证成员节点的日志的完整性。

   

     如果爸爸节点宕机导致爸爸节点发生切换,此时新的爸爸节点会把nextlndex和matchlndex重置,nextlndex重置为自身最后一条已提交的日志索引(上面提到的commitlndex),
matchlndex重置为0,新的爸爸节点会从nextlndex开始的所有日志到个个成员和节点,如果对应成员节点发现日志的索引值比自己最后一条提交的索引值大,就会认为自己丢失了一些日志,返回追加失败,爸爸节点收到失败响应后前移对应的nextlndex重试,如果成员节点发现该日志比自己最后一条提交的索引值小就会直接返回成功,爸爸节点收到成功的响应后更新对应的nextlndex和matchlndex后后移nextlndex继续复制日志。

3 leader切换时如何保证日志完整性

     回到最开始的leader选举部分(见C2),实际上成员节点首次收到某个节点的选举请求时并不是直接就将选票投给哪个Candidate节点, Follower 节点还需要比较该 Candidate 节点的日志记录与自身的日志记录,如果发起选举节点的日志没有自己的日志新,就会投出拒绝票,确保将选票投给包含了全部己提交(commited)日志记录的 Candidate 节点。这也就保证了己提交的日志记录不会丢失,Candidate 节点为了成为 Leader 节点,必然会在选举过程中向集群中半数以上的节点发送选举请求,因为己提交的日志记录必须存在集群中半数以上的节点中,这也就意味着每一条己提交的日志记录肯定在这些接收到节点中的至少存在一份。

三 参考文献

一文搞懂Raft算法 - xybaby - 博客园

raft流程动画演示

共识算法:Raft - 简书

etcd技术内幕

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值