【分布式】图解Raft协议

一、分布式共识(Distributed Consensus)

当系统中只有1个节点(下图蓝色,你可以理解为一个存储数据的数据库)。如果客户端(绿色)发送1个x=8的数据给数据库,数据库会立即将X更改为8。由于只有1个数据库节点,对于X的值,很快就会达成一致:x=8。

But,如果有多个数据库节点呢?如图,假设3个数据库节点中x的值都为7。客户端发送更改x=8 的请求,3个数据库节点有2个节点更新成功,x=8;另一个节点更新失败,存储的x仍然是7。这样就会出现对于同一个变量x的值,3个节点存储的数值不一样。这就是分布式共识的问题。
在这里插入图片描述

二、分布式共识解决方案 - Raft协议

Raaft是用来解决分布式共识的一种协议。Raft协议中定义了3种角色:

  • Follower
  • Candidate
  • Leader
    在这里插入图片描述

首先我们简单介绍下Raft协议中最重要的两个部分:Leader选举和日志复制两个过程。

1、Leader选举过程(Leader Election)

每个节点初始状态都是跟随者Follower。当一个Follower节点不再听从Leader节点,那么该节点就会变为候选者Candidate。

紧接着,候选者节点会发送投票请求给所有节点,请求他们给自己投票,让自己当选为Leader节点,每个节点收到该请求之后就会返回投票响应。如果候选者节点获取到了大部分节点的投票,那么他就成为了新的Leader。

这个过程如下(左下角节点为Candidate节点,发起投票,收到大部分节点响应之后成为Leader节点):
在这里插入图片描述

2、日志复制(Log Replication)

客户端的请求首先会被Leader节点处理,每个数据的修改都会被放入该节点的日志中,处于未提交的状态(比如,此时Leader节点中X值仍然是之前的值)。

之后Leader节点会将修改的数据发送给Follower节点,Follower节点收到Leader节点发送的数据之后就会写入自身的日志段,之后再响应给Leader节点。

当Leader节点收到大部分Follower节点的写入完成响应之后,Leader节点就会进行提交,将x的值改为新的值:5.,然后再通知给各个Follower进行日志提交。

以上步骤之后,集群中的节点对于数据X的值达成了共识,即X = 5.
在这里插入图片描述

三、Leader选举详细过程

Raft算法中有两个超时控制:

  • 选举超时(election timeout)
  • 心跳超时(heartbeat timeout)

1、选举超时(election timeout)

Server启动时,各个节点初始状态均为Follower,每个节点会给自己设置一个选举超时时间(一般为150~300ms);

如果在各自设置的超时时间内收到来自Leader或Candidate的心跳消息,则定时器重启;否则会发起一次选举过程,向其他服务器发出选举自己的请求(先超时的节点先发起投票);

其他节点在编号为1的任期内未投票,则将选票投给节点A,并增加自己的任期编号.

举个例子:

假设Node A、Node B、Node C 3个节点election timeout分别是200ms、210ms、150ms。

如果未收到心跳消息,Node C的election timeout首先过期,Node C会给自己投上一票,Vote Count: 1,任期Term也设置为1(每个节点的Term为0,每投一票加1),

然后发起【选我当Leader】的请求给其他follower节点:Node A和Node B。如果在该任期内(Term = 1)其他节点都未投票,则会给Node C投票,并重置自己的election timeout;否则拒绝投票。当Node C收到大多数投票之后,就会成为Leader。
在这里插入图片描述

2、心跳超时(heartbeat timeout)

当Node C成为Leader之后,会以heartbeat timeout时间间隔不断发送【追加日志】的消息给Follower节点Node A和Node B,在该期间内,Node A和Node B会接收Node A的请求,追加到各自的日志中。
在这里插入图片描述

3、重新选举

让我们看下如果Leader节点挂了之后重新选举的过程。

如果Follower在heartbeat timeout时间内未收到Leader发送的心跳消息,率先超时的节点就会成为candidate,重新发起选举过程。

假设Leader 节点Node B宕机,Node A和Node C在heartbeat timeout时间内未收到Leader节点发送的消息,Node C率先超时成为candidate,然后向其他节点发起【选我当Leader】的投票请求,并且Term任期升级为2。

在任期为2的期间内,Node A未给别的投票请求作出响应,所以可以给Node C投票。Node C获取了多数选票(包括自己给自己投的一票),这样Node C就成为了新的Leader。
在这里插入图片描述

假设有4个节点,其中两个节点同时发起选举过程,并同时获取到相同选票,这时又该如何处理?
在这里插入图片描述

如上图所示,Node B和Node D同时超时成为候选者,然后同时发起投票请求,Node B和Node D在任期为4期间分别获取到Node A和Node C的投票,这样Node B和Node D获得相同票数2,无法选举出Leader,会继续等待。

在下一个heartbeat timeout之后,Node C率先超时并发起投票过程,最终获取大多数票数成为新的Leader节点。

四、日志复制详细过程

Raft算法中,Leader节点收到来自客户端请求后,会将处理过程中以复制和应用日志项到状态机中。为了实现数据一致性,会将日志同步到跟随者节点中,副本数据是以日志的形式存在。Raft中日志必须是连续的。
在这里插入图片描述

下面看看日志复制的详细过程以及发送【追加条目】的过程。

  • 首先Leader节点Node A收到客户端(绿色节点)发送的值修改请求:将X改为5,Leader节点(Node A)将x值改为5后但是并不提交此变更,而是创建一个新日志项,追加到本地日志中。再将此次的变更发送给Follower节点。

  • Follower节点(Node B、Node C)收到该请求之后会将日志复制到本地,并返回响应给领导者节点;

  • 当Node A收到大部分Follower节点的响应之后,就会将自己本地的变更(x=5)提交,同时让所有ollower节点提交变更;

  • 领导者将日志项应用到日志项中之后,没有必要发送消息通知跟随者,而是通过心跳响应或者下次的日志RPC消息,通知跟随者将该日志项应用到其本地状态机中;

这样3个节点对于x=5的值就保持一致了。
在这里插入图片描述

我们再发送一条ADD 2的指令,回顾下上述过程:
在这里插入图片描述

五、Raft处理网络分区

如果出现网络分区,Raft也是处理的的?

假设初始状态如下,Node B为Leader节点,不断发送心跳消息给各个Follower节点。
在这里插入图片描述

假设出现网络分区,Node A、Node B在一个网络内,而Node B、Node C和Node D在另一个网络内。当Node C、Node D、Node E收不到Node B节点的心跳消息之后,就会发起选举,假设Node D获得3票成为Leader。

此时两个分区的Leader节点分别为Node D和Node B。
在这里插入图片描述

当增加一个客户端节点。客户端1(下面的绿色节点)尝试将x改为3时,发送请求给分区1。Node B节点接收到请求并且发送给所有Follower节点、由于只能收到Node A的响应,所以提交失败,x=3无法修改成功。

客户端2(上面的绿色节点)尝试将x改为8时,发送请求给分区2。Node D节点收到请求并且发送给所有Follower节点,收到Node C和Node D的响应,修改成功。
在这里插入图片描述

当网络恢复之后,Node B发现有更高的任期之后(就会明白有新的Leader出现),就会停止复制,Node B和Node A会回滚之前未提交的日志,并且会同步新的Leader Node D的日志。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/noaman_wgs/article/details/108260615