raft协议用途,raft协议的应用

  

  来源:阿飞的博客   

  

  分布式一致性   

  

  假设我们有一个单节点系统,它充当数据库服务器,然后存储一个值(假设是X)。然后,客户端向服务器发送一个值(比如8)。只要服务器接受这个值,这个值在单个节点上的一致性就很容易保证:   

  

     

  

  单机环境   

  

  但是如果数据库服务器有多个节点呢?比如如下图所示,有A、B、c三个节点,此时客户端操作这个由三个节点组成的数据库集群时,如何保证值的一致性,就是分布式一致性问题。Raft是分布式一致性协议(还有其他一致性算法,如ZAB、PAXOS等。):   

  

     

  

  分布式环境   

  

  在解释Raft算法之前,一些概念,先普及一下Raft协议中涉及的一些概念:   

  

  term:任期,如新的选举任期,即当整个集群初始化,或新的领导人选举将开始一个新的选举任期。   

  

     

  

  大多数:假设一个集群由N个节点组成,那么它们中的大多数至少是N/2 1。比如:3个节点的集群,大部分至少是2个;一个由5个节点组成的集群,其中大多数节点至少有3个。   

  

  状态:每个节点有三种状态,在某一时刻只能是三种状态之一:追随者(左)、候选人(右)和领导者。假设三种状态不同模式如下:   

  

     

  

  节点状态图   

  

  状态初始化时,三个节点都处于跟随状态,项为0,如下图所示:   

  

     

  

  初始化   

  

  Leader选举领导人选举需要一定的投票节点。在决定哪个节点将投票给其他节点之前,每个节点将分配一个随机的选举超时。在此期间,节点必须等待,不能成为候选状态。现在假设节点A等待168ms,节点B等待210ms,节点C等待200 ms,由于A的等待时间最短,它将是第一候选,它将向另外两个节点发起投票请求,希望它们能够选举自己为领导者:   

  

     

  

  发起投票请求   

  

  另外两个节点收到请求后,假设它们的投票会返回给候选状态节点A,结果节点A会从候选变为领导,如下图所示。这个过程被称为Leader选举(领导人选举)。接下来,这个分布式系统中的所有更改都必须首先经过节点A,即领导节点:   

  

     

  

  领导者节点   

  

  如果在某个时刻,追随者不再收到领导者的消息,它将成为候选人。然后要求其他节点给他投票(类似拉票)。其他节点会回复它的投票结果,如果它能得到大多数节点的选票,就能成为新的领袖。   

  

     

  

  假设日志复制的客户端接下来发起对SET 5的请求,该请求首先被领导者即节点A接收,节点A写日志。由于任何其他节点都没有收到该日志,因此其状态为uncommitted.   

om/pic/img.php?k=raft协议用途,raft协议的应用10.jpg">

  

sc_20190511173101.png

  

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

  

  

日志复制

  

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

  

  

sc_20190511173806.png

  

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

  

  

sc_20190511174011.png

  

两个超时接下来介绍Raft中两个很重要的超时设置:选举超时和心跳超时。

  

选举超时

  

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

  

  

选举超时

  

心跳超时

  

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

  

  

心跳超时

  

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

  

  

re-election

  

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

  

  

新Leader节点

  

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

  

  

2个Candidate节点

  

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

  

  

sc_20190511214801.png

  

我们假设节点A能得到大多数投票,那么接下来节点A就会成为新的Leader节点,并且任期term加1:

  

  

sc_20190511215048.png

  

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

  

  

5个节点的集群

  

我们假设发生了网络分区:节点A和B在一个网络分区,节点C、D和E在另一个网络分区,如下图所示,且节点B和节点C分别是两个网络分区中的Leader节点:

  

  

发生网络分区

  

我们假设还有一个客户端,并且往节点B上发送了一个SET 3,由于网络分区的原因,这个值不能被另一个网络分区中的Leader即节点C拿到,它最多只能被两个节点(节点B和C)感知到,所以它的状态是uncomitted(红色):

  

  

操作1

  

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

  

  

操作2

  

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

  

相关文章