竞选机制之Raft协议解析

目录

分布式一致性

 Raft基础概念

leader选举

日志复制

超时机制

重新选举

竞选失败

网络分区 


在讲解Raft协议之前,首先要了解一下什么是分布式一致性?

分布式一致性

假设,现有某个单节点的系统,且作为数据库服务器,其中,存储了一个值X。此时,用户通过事务操作修改了这个值。由于这个是单节点的系统,数据库只需要接收这个值并进行保存即可,这个值在单节点上的一致性非常容易保证。

但是,如果数据库服务器有多个节点呢?比如,如下图所示,有三个节点:a,b,c。这时候客户端对这个由3个节点组成的数据库集群进行操作时的值一致性如何保证,这就是分布式一致性问题。而Raft就是一种实现了分布式一致性的协议(还有其他一些一致性算法,例如:ZAB、PAXOS等):


 Raft基础概念

 状态:每个节点有三种状态,且某一时刻只能是三种状态中的一种:Follower(图左),Candidate(图中),Leader(图右)。假设三种状态不同图案如下所示:

  • leader:集群中的管理者,所有client的流量都从leader这里经过,正常情况下只有一个leader,会周期性的向follower发出心跳维持统治。当发现自己不是leader的时候会转为follower。
  • follower:集群中的被管理者,只会对其它服务器的命令做出响应。在长时间得不到leader响应之后会转为candidate。
  • candidate:集群的候选者,会发起投票试图当选leader。 

term:任期,比如新的选举任期,即整个集群初始化时,或者新的Leader选举就会开始一个新的选举任期。

原理:为了解决选举中的冲突问题以及各种数据冲突的问题,raft将时间划分为term,每个term是一个连续递增的数字,保存在每个服务器的内存中,在term的最初一定是选举阶段,当leader诞生之后,这个term的剩余时间里整个raft集群堆外提供正常的服务,如果没有发生异常,这个term将一直持续下去;如果发生异常(比如leader挂掉),那么当前term将结束,服务器递增term,然后进行新一轮的选举。term的连续状态示意图如下

所以term在raft协议中实际是作为逻辑时钟角色存在的,它对raft服务器的影响是:只有处在最新term的服务器和消息才是安全有效的。服务器会在消息中交换自己的当前term,如果服务器发现自己的term比某个term更小,那么服务器会更新自己的term;如果服务器是leader或者candidate, 那么还会立即转化为follower(前提是,term大于自身,且log不旧与自身log,关于log会在后续讲到)。如果服务器接收到的消息的term小于自己的term,那么会认为此消息无效

raft中每个term的通信消息分为两种:RequestVote RPC用在投票过程(candidate发起),AppendEntries RPC用来复制日志和进行heartbeat通信(leader 发起)。如果在指定时间内没有得到响应,服务器会不停的重试(对于实现很重要)。


大多数:假设一个集群由N个节点组成,那么大多数就是至少N/2+1。例如:3个节点的集群,大多数就是至少2;5个节点的集群,大多数就是至少3。

Raft的实现分为四块,leader选举,日志复制,集群状态变更,日志压缩,以下,将分模块讲解


leader选举
 

 初始化状态时,三个节点都是Follower状态,并且term为0,如下图所示:

 

Leader选举需要某个节点发起投票,在确定哪个节点向其他节点发起投票之前,每个节点会分配一个随机的选举超时时间(election timeout)。在这个时间内,节点必须等待,不能成为Candidate状态。现在假设节点a等待168ms , 节点b等待210ms , 节点c等待200ms 。由于a的等待时间最短,所以它会最先成为Candidate,并向另外两个节点发起投票请求,希望它们能选举自己为Leader:

另外两个节点收到请求后,假设将它们的投票返回给Candidate状态节点a,节点a由于得到了大多数节点的投票,就会从Candidate变为Leader,如下图所示,这个过程就叫做Leader选举(Leader Election)。 接下来,这个分布式系统所有的改变都要先经过节点a,即Leader节点。此时,leader会通过heartbeat心跳和follower之间保持通信(注意heartbeat time interval<<min(election timeout),倘若心跳间隔大于了竞选超时时长的话,就会导致,leader心跳还没有发送到follower,follower的竞选超时时间就已经满足条件,

开始进行leader的竞选)

如果某个时刻,Follower不再收到Leader的消息,它就会变成Candidate。然后请求其他节点给他投票(类似拉票一样)。其他节点就会回复它投票结果,如果它能得到大多数节点的投票,它就能成为新的Leader。

问题 选举超时时长一致会导致什么问题呢?

但是,这里可能会存在split votes的现象。倘若,节点a,b,c生成的选举超时时长一致,那么,就会陷入一个尴尬的局面,三者全部都投票给自己,三者都无法获取倒大多数节点的投票, 就会导致竞选失败的现象。详情见竞选失败

好在Raft协议在生成选举超时时长时,采用的是random election timeout机制。他会随机生成超时时长,这样就能保证了split votes发生的几率很小,避免反复竞选失败的现象。

random election timeout可见:超时机制


日志复制

假设接下来客户端发起一个SET 5的请求,这个请求会首先由leader即节点a接收到,并且节点a写入一条日志。由于这条日志还没被其他任何节点接收,所以它的状态是uncommitted

为了提交这条日志,Leader会将这条日志通过心跳消息复制给其他的Follower节点:

 

 一旦有大多数节点成功写入这条日志,那么Leader节点的这条日志状态就会更新为committed状态,并且值更新为5: 

 

 Leader节点然后通知其他Follower节点,其他节点也会将值更新为5。如下图所示,这个时候集群的状态是完全一致的,这个过程就叫做日志复制(Log Replication):


超时机制

 Raft协议中,主要包含两个重要的超时机制:选举超时心跳超时

  • 选举超时

为了防止3个节点(假设集群由3个节点组成)同时发起投票,会给每个节点分配一个随机的选举超时时间(Election Timeout),即从Follower状态成为Candidate状态需要等待的时间。在这个时间内,节点必须等待,不能成为Candidate状态。如下图所示,节点C优先成为Candidate,而节点A和B还在等待中:

  • 心跳超时

如下图所示,节点A和C投票给了B,所以节点B是leader节点。节点B会固定间隔时间向两个Follower节点A和C发送心跳消息,这个固定间隔时间被称为heartbeat timeout。而心跳信息中,包含了推送给Follower的日志信息,Follower节点收到每一条日志信息都需要向Leader节点响应这条日志复制的结果:


重新选举

选举过程中,如果Leader节点出现故障,就会触发重新选举。如下图所示,Leader节点B故障(灰色),这时候节点A和C就会等待一个随机时间(选举超时),谁等待的时候更短,谁就先成为Candidate,然后向其他节点发送投票请求: 

如果节点A能得得到节点C的投票,加上自己的投票,就有大多数选票。那么节点A将成为新的Leader节点,并且Term即任期的值加1更新到2:

竞选失败

值得注意的是,每个选举期只会选出一个Leader。假设同一时间有两个节点成为Candidate(它们随机等待选举超时时间刚好一样),如下图所示,并且假设节点A收到了节点B的投票,而节点C收到了节点D的投票: 

这种情况下,就会触发一次新的选举,节点A和节点C又等待一个随机的选举超时时间,直到一方胜出:

 

我们假设节点A能得到大多数投票,那么接下来节点A就会成为新的Leader节点,并且任期term加1,并且会发送心跳报文至其他Follower去更新任期term


网络分区 

 在发生网络分区的时候,Raft一样能保持一致性。如下图所示,假设我们的集群由5个节点组成,且节点B是Leader节点:

假设发生了网络分区:节点A和B在一个网络分区,节点C、D和E在另一个网络分区.此时,节点C,D,E收不到leader的心跳信息,会重新开始leader选举。假设C成功竞选leader,任期term加1,D,E节点收到心跳信息后,term也加1.

倘若还有一个客户端,并且往节点B上发送了一个SET 3,由于网络分区的原因,这个值不能被另一个网络分区中的Leader即节点C拿到,它最多只能被两个节点(节点B和A)感知到(不满足大多数节点接收到log的条件),所以它的状态是uncomitted(红色),因此,这个log的复制就是失败的:

 

另一个客户端准备执行SET 8的操作,由于可以被同一个分区下总计三个节点(节点C、D和E)感知到,3个节点已经符合大多数节点的条件。所以,这个值的状态就是committed:

网络恢复

接下来,我们假设网络恢复正常,如下图所示。节点B能感知到C节点这个Leader的存在,它就会从Leader状态退回到Follower状态(因为B的term小于C的term,且日志也旧与C),并且节点A和B会回滚之前没有提交的日志(SET 3产生的uncommitted日志)。同时,节点A和B会从新的Leader节点即C节点获取最新的日志(SET 8产生的日志),从而将它们的值更新为8。如此以来,整个集群的5个节点数据完全一致了:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值