[搜狐科技]由浅入深理解raft协议

jinanxiaolaohu jinanxiaolaohu     2023-02-08     429

关键词:

由浅入深理解Raft协议

0 - Raft协议和Paxos的因缘

读过Raft论文《In Search of an Understandable Consensus Algorithm》的同学都知道,Raft是因为Paxos而产生的。Paxos协议是出了名的难懂,而且不够详细,紧紧依据Paxos这篇论文开发出可用的系统是非常困难的。Raft的作者也说是被Paxos苦虐了无数个回合后,才设计出了Raft协议。作者的目标是设计一个足够详细并且简单易懂的“Paxos协议”,让开发人员可以在很短的时间内开发出一个可用的系统。

Raft协议在功能上是完全等同于(Multi)-Paxos协议的。Raft也是一个原子广播协议(原子广播协议参见《由浅入深理解Paxos协议(1)》),它在分布式系统中的功能以及使用方法和Paxos是完全一样的。我们可以用Raft来替代分布式系统中的Paxos协议如下图所示:

技术分享图片

1 - Raft的设计理念

严格来说Raft并不属于Paxos的一个变种。Raft协议并不是对Paxos的改进,也没有使用Paxos的基础协议(The Basic Protocol)。Raft协议在设计理念上和Paxos协议是完全相反的。正是由于这个完全不同的理念,使得Raft协议变得简单起来。

Paxos协议中有一个基本的假设前提:可能会同时有多个Leader存在。这里把Paxos协议执行的过程分为以下两个部分:

  • Leader选举

  • 数据广播

在《由浅入深理解Paxos协议(2)》的“Leader的选取”一节中提到过,Paxos协议并没有给出详细的Leader选举机制。Paxos对于Leader的选举没有限制,用户可以自己定义。这是因为Paxos协议设计了一个巧妙的数据广播过程,即Paxos的基本通讯协议(The Basic Protocol)。它有很强的数据一致性保障,即使在多个Leader同时出现时也能够保证广播数据的一致性。

而Raft协议走了完全相反的一个思路:保证不会同时有多个Leader存在。因此Raft协议对Leader的选举做了详细的设计,从而保证不会有多个Leader同时存在。相反,数据广播的过程则变的简单易于理解了。

2 - Raft的日志广播过程

为了保证数据被复制到多数的节点上,Raft的广播过程尽管简单仍然要使用多数派协议,只是这个过程要容易理解的多:

  1. 发送日志到所有Followers(Raft中将非Leader节点称为Follower)。

  2. Followers收到日志后,应答收到日志。

  3. 当半数以上的Followers应答后,Leader通知Followers日志广播成功。

- 日志和日志队列

Raft将用户数据称作日志(Log),存储在一个日志队列里。每个节点上都有一份。队列里的每个日志都一个序号,这个序号是连续递增的不能有缺。

技术分享图片

日志队列里有一个重要的位置叫做提交日志的位置(Commit Index)。将日志队列里的日志分为了两个部分:

  • 已提交日志:已经复制到超过半数节点的数据。这些日志是可以发送给应用程序去执行的日志。

  • 未提交日志:还未复制到超过半数节点的数据。

技术分享图片

当Followers收到日志后,将日志按顺序存储到队列里。但这时Commit Index不会更新,因此这些日志是未提交的日志,不能发送给应用去执行。当Leader收到超过半数的Followers的应答后,会更新自己的Commit Index,并将Commit Index广播到Followers上。这时Followers更新Commit Index,未提交的日志就变成了已提交的日志,可以发送给应用程序去执行了。

从上面的解释我们可以知道,日志队列中已经提交的日志是不可改变的,而未提交的日志则可以被更新成其他的日志(在Leader发生变化时会发生)。

Raft的日志队列和《》中的“预存储队列+存储队列”功能是一样的,但是巧妙的合并到了一起。这样做解决的问题和中“预存储队列+存储队列”解决的问题也是一样的,这里就不再叙述。

3 - Raft的Leader选举

Raft称它的Leader为“Strong Leader”。Strong Leader 有以下特点:

  • 同一时间只有一个Leader

  • 只能从Leader向Followers发送数据,反之不行。

下面我们看一下Raft通过哪些机制来实现Strong Leader。

- 多数派协议

为了保证只有一个Leader被选举出来,选举的过程使用了多数派协议。这样很好理解,当一个Candidate(申请成为Leader的节点)请求成为Leader时,只有半数以上的Followers同意后,才能成为Leader。投票过程如下:

  1. 当发现Leader无响应后(一段时间内没有日志或心跳),Candidate发送投票请求。

  2. Followers投票。

  3. 如果超过半数的Followers投了票,则Candidate自动变成Leader,开始广播日志。

- 随机超时机制

和《由浅入深理解Paxos协议(1)》中提到问题一样,这里也会发生多个Candidate同时发送投票请求,而导致谁都不能够得到多数赞成票的情况,有可能永远也选不出Leader。为了保证Leader选举的效率,Raft在投票选举中使用了随机超时的机制:

  1. 在每个Followers上设定的Leader超时时间是在一个范围内随机的。这样可以尽量让Followers不在同一时间发起Leader选举。

  2. 每个Candidate发起投票后,如果在一段时间内没有任何Candidate称为Leader则,需要重新发起Leader选举。这段等待的时间,在每个Candidate上也是随机的。从而保证不会有多个Candidate同时重新发起Leader选举。

虽说是随机的超时时间,但是也有个范围,太小或者太大都会影响系统的可用性。太小会导致过多的选举冲突,太大又会影响系统的平滑运行。在Raft的论文中,作者将这个超时时间称为electionTimeout,并给出了合理的范围,公式如下:

broadcastTime ? electionTimeout ? MTBF

“?”代表数量级上的差异(10倍以上)。

- Candidate的日志长度要等于或者超过半数节点才能选为Leader

当Leader故障时,Followers上日志的状态很可能是不一致的。有的多有的少,而且Commit Index也不尽相同。

技术分享图片

我们知道已经提交的日志是不能够丢弃的,必须要最终复制到所有的节点上才行。假如在选Leader时,图中Candidate A变成了Leader,就必须要首先从Candidate B上将日志4复制过来,然后才能开始处理新的日志。为了减少复杂性,raft就规定,只有包含了所有已提交日志的Candidate才能当选为Leader。

实现也很简单:

  • 当发现Leader无响应后(一段时间内没有数据或心跳),Candidate发送投票请求,请求中包含自己日志队列的长度(或者说最大日志的Index)。

  • Followers检查Candidate的日志长度,只有Candidate的日志等于或者长于自己才投票。

  • 如果超过半数的Followers投了票,则Candidate自动变成Leader,开始广播数据。

因为已经提交的日志一定被复制到了多数节点上,所以日志长度等于或者长于多数节点的Candidate一定包含了所有已经提交的日志。

为什么不是检查Commit Index?

因为Leader故障时,很有可能只有Leader的Commit Index是最大的。

技术分享图片

如果图中的Candidate A被选举为Leader,那么日志4就会被丢弃。但是日志4已经在原来的Leader上提交了,因此必须被保留才行。所以只能让日志长度更长的Candidate B选为Leader。这种做法有可能把原来Leader没广播完成的日志(图中的日志5)接着广播完成,这没有什么关系。

- Followers日志补齐

当Leader故障时,Followers上的日志状态是不一样的,有长有短。因此新的Leader选出后,首先要将所有Followers的日志补齐才行。因此Leader要询问Followers的日志长度,从最小的日志位置开始补齐。

- Followers未提交日志的更新

新Leader的日志一定包含所有已经提交的日志。但新Leader的日志不一定是最长的,那些新Leader没有的日志,一定是未提交的日志,因此可以被更新,没有关系的。Leader只需要从自己的当前位置开始插入日志并广播出去就可以了。Followers会用新的日志去更新指定位置上的日志。

4 - 新旧Leader的交替

新的Leader选出后,开始广播日志。这时如果旧的Leader故障恢复了(比如网络临时中断),并且还认为自己是Leader,也会广播日志。这不就导致了同时有两个Leader出现吗?是的,Raft也没办法让旧的Leader不发日志,但是Raft有办法让Followers拒绝旧Leader的日志。

- Term

Raft将时间划分为连续的时间段,称为Term。 Term是指从一次Leader选举开始到下一次Leader选举的一段时间。这段时间内只能有一个Leader被选举成功,并负责管理系统或者没有Leader选出。

技术分享图片

Raft论文上的Term图片

每个Term都有一个唯一的数字编号。所有Term的数字编号是从小到大连续排列的。

- 作废旧Leader

Term编号在作废旧Leader的过程中至关重要,但却十分简单。过程如下:

  1. 发送日志到所有Followers,Leader的Term编号随日志一起发送。

  2. Followers收到日志后,检查Leader的Term编号。如果Leader的Term编号等于或者大于自己的当前Term(Current Term)编号,则存储日志到队列并且应答收到日志。否则发送失败消息给Leader,消息中包含自己的当前Term编号。

  3. 当Leader收到任何Term编号比自己的Term编号大的消息时,则将自己变成Follower。收到的消息包括:Follower给自己的回复消息、新Leader的日志广播消息、Leader的选举消息。

- Raft的实现

论文中作者仅用了两个RPC就实现了Raft的功能,它们分别是:

  • RequestVote() Candidate发起的投票请求

  • AppendEntries() 将日志广播到Followers上

AppendEntries()除了广播日志外,作者还巧妙的用它实现了以下的功能:

  • 发送心跳(heartbeat): 没有客户日志时,通过AppendEntries()广播空日志,当做心跳。

  • 发送Commit Index:当Commit Index更新后,可以随着当前的日志通过AppendEntries()广播到Followers上。如果没有客户端日志,则可以随着心跳广播出去。

欢迎订阅我的公众号"MySQL代码研究",这个公众号里的文章,多数是我在开发过程中学习、研究MySQL代码和相关技术的总结和笔记,希望会对你有帮助。返回搜狐,查看更多

分布式raft算法

....github.io/http://thesecretlivesofdata.com/raft/这里有一个非常适合理解raft协议的小动画。1.1.1简介概念:raft是一种用于管理log复制的一致性协议,它和paxos有同样功能,但是比它简单容易理解。功能:leader选 查看详情

一致性算法--raft

...里面包含了大量的论文,视屏已经动画演示,非常有助于理解协议。概念与术语leader:领导者,提供客户提供服务(生成写日志)的节点,任何时候raft系统中只 查看详情

分布式一致性算法--raft

...里面包含了大量的论文,视屏已经动画演示,非常有助于理解协议。概念与术语leader:领导者,提供客户提供服务(生成写日志)的节点,任何时候raft 查看详情

raft

...有一个重要特征就是提高系统的可靠性。提供可靠性可以理解为系统中一台或多台的机器故障不会使系统不可用(或者丢失数据)。保证系统可靠性的关键就是多副本(即数据需要有备份),一旦有多副本,那么久面临多副本之... 查看详情

raft协议实战之redissentinel的选举leader源码解析

...s被认为是解决分布式系统一致性的代名词。但是Paxos难于理解,更难以实现,诸如Google大牛们开发的分布式锁系统Chubby都遭遇了 查看详情

《分布式一致性协议raft简介》

...下游server配置中心等场景。但是ZAB和paxos有个缺点,就是理解性比较差。其论文内容十分复杂,导致真正理解的开发人员非常少。【知乎:raft算法与paxos算法相比有什么优势,使用场景有什么差异】【rafthomepage】【raftpaper】【live... 查看详情

分布式共识算法——gossip协议(图解)

...法,大家首先想到的应该都是Raft、Paxos、Zab算法这类理解起来比较困难的强一致性算法。但是还有一个弱一致性的共识算法比较好理解,Gossip协议。与Paxos和Raft目标是强一致性不同&# 查看详情

分布式共识算法——gossip协议(图解)

...法,大家首先想到的应该都是Raft、Paxos、Zab算法这类理解起来比较困难的强一致性算法。但是还有一个弱一致性的共识算法比较好理解,Gossip协议。与Paxos和Raft目标是强一致性不同&# 查看详情

raft协议处理各种failover情况

Raft协议处理各种failover情况Raft协议的易理解性描述虽然Raft的论文比Paxos简单版论文还容易读了,但论文依然发散的比较多,相对冗长。读完后掩卷沉思觉得还是整理一下才会更牢靠,变成真正属于自己的。这里我就... 查看详情

对标eureka的ap一致性,nacos如何实现raft算法(代码片段)

...于一个管理日志一致性的协议,相比于Paxos协议Raft更易于理解和去实现它。为了提高理解性,Raft将一致性算法分为了几个部分,包括领导选取(leaderselection)、日志复制(logreplication)、安全(safety),并且使用了更强的一致性... 查看详情

对标eureka的ap一致性,nacos如何实现raft算法(代码片段)

...于一个管理日志一致性的协议,相比于Paxos协议Raft更易于理解和去实现它。为了提高理解性,Raft将一致性算法分为了几个部分,包括领导选取(leaderselection)、日志复制(logreplication)、安全(safety),并且使用了更强的一致性... 查看详情

raft协议

what:  raft是分布式的一致性协议(Consensus),其相对pasox更加简单。用来保障servers上副本一致性的一种算法。  一致性协议是为了确保容错性,也就是即使系统中有一两个服务器当机,也不会影响其处理过程 how:  ... 查看详情

raft算法

...于Multi-Paxos的基础上做了简化和限制。不同于Paxos的难以理解,Raft设计的首要目的就是可理解性,一个易于理解、实现简单的分布式一致性协议。Raft将一致性算法分解成了几个关键模块,例如领导人选举、日志复制和安全性,本... 查看详情

raft算法原理剖析

...态变量中,状态机的变量只能通过外部命令来改变。简单理解的话,可以想象成是一组服务器,每个服务器是一个状态机,服务器的运行状态只 查看详情

raft算法和gossip协议

简单介绍下集群数据同步,集群监控用到的两种常见算法。Raft算法raft集群中的每个节点都可以根据集群运行的情况在三种状态间切换:follower,candidate与leader。leader向follower同步日志,follower只从leader处获取日志。在节点初始启动... 查看详情

raft协议(代码片段)

...Paxos相去甚远。为了解决以上问题,另一个高性能且易于理解的一致性算法横空出世:Raft基本概念Raft算法基于复制状态机ReplicatedStateMachine模型,本质上就是一个管理日志复制的算法。Raft集群采用SingleLeader架构,集群中有唯一的... 查看详情

分布式一致性算法:raft算法

...。本文对raft论文进行翻译,希望能有助于读者更方便地理解raft的思想。如果对Paxos算法感兴趣,可以看我的另一篇文章:分布式系列文章——Paxos算法原理与推导摘要Raft是用来管理复制日志(replicatedlog)的一致性协议。它跟mult... 查看详情

手撸golang学etcd手写raft协议之12单元测试

手撸golang学etcd手写raft协议之12单元测试缘起最近阅读[云原生分布式存储基石:etcd深入解析](杜军,2019.1)本系列笔记拟采用golang练习之raft分布式一致性算法分布式存储系统通常会通过维护多个副本来进行容错,以提高系统的可用... 查看详情