Raft

Part 03:Raft论文翻译-《CONSENSUS: BRI

2021-07-31  本文已影响0人  Number9527

3. 基础Raft算法

本章介绍了Raft算法。我们努力将Raft算法设计的更容易理解;第一部分描述了我们的可理解性设计方法。接下来的部分描述了Raft算法本身,并包括了我们为可理解性所做的设计抉择。

3.1 为可理解而设计

我们在设计Raft算法时有几个目标:它必须为系统建设提供一个完整和实用的算法基础,从而显著减少开发人员所需的设计工作;它必须在所有条件下都是安全的,在典型操作条件下可用;它必须对常规的操作保持高效。但我们最重要的目标,也是最困难的挑战,是可Raft算法的可理解性。必须使得大量读者能够轻松地理解该算法。此外,必须能够直观的指导开发者进行算法的工程化开发,以便系统构建者能够实现面对问题时所采取的不可避免的算法扩展。

在Raft的设计中,我们不得不面临在多种可行方法中的抉择。在这些情况下,我们基于可理解性来评估替代方案:评估解释每种替代方案有多难(例如,它的状态空间有多复杂,它有复杂的隐含内容/信息?),并试图评估读者要完全理解Raft算法及其隐含的信息会有多容易呢?

我们认识到,这种分析具有高度的主观性,虽然如此,我们还是使用了两种可行的技术来进行评估。第一种是问题解构(将一个大问题分解成多个小问题),例如我们将Raft算法整体上拆分成了Leader Election、Log Replication和Safety三个部分。第二个方法是通过减少需要考虑的状态来减少状态机的状态空间,尽可能使得共识算法具有有条理并且消除其中的不确定性。具体来说,Raft算法不容许日志中具有空洞(空洞就是在某个条目上没有相应的内容,而后面的条目却有内容,这是Paxos算法的一个缺点),而且Raft算法限制了日志产生不一致的可能性(通过Leader选举的限制以及只有Leader作为主数据源的限制,保证了Follower之间不会存在日志内容的互相传输,只要与Leader保持一致就好,减少了各个服务器上日志不一致的可能性)。虽然我们极力的避免算法中的不确定性,但是有的时候我们也通过这种不确定性来增强算法的可理解性(这就是以可理解性为首要目标的表现),例如,随机的方法引入了不确定性,但是这可以减少状态空间(通过随机的方法来避免处理系统中出现的需要处理多种可能的问题,如在Leader选举的时候,不同的Candidate通过超时来进行下一轮选举的发起,这样避免了Raft算法来处理每个算法无法胜选的情况)。

3.2 Raft概览

Raft算法是一种管理第2.1节所述形式的日志副本的算法。图3.1总结了算法以供参考,图3.2列出了算法的关键属性;本章其余部分分段讨论。

Raft首先选择一个服务器作为Leader,然后让领导者完全负责管理系统中的日志副本。Leader接受从客户端Client获取的日志条目(Log Entry),在其他服务器上复制它们,并告诉服务器何时将日志条目应用到其状态机是安全的。通过Leader管理这种方式简化日志副本的管理。例如,Leader可以在不咨询其他服务器的情况下决定在日志中放置新条目,并且数据以简单的方式从头Leader流到其他服务器(Follower或者Candidate)。Leader可能发生故障或与其他服务器断开,在这种情况下,一个新的Leader会被选出来。

通过基于Leader的方法,Raft算法将共识问题分解为三个相对独立的子问题:

在介绍了Raft共识算法之后,本章讨论了可用性问题和系统中计时的作用(第3.9节),以及在服务器之间Leader转换的可选扩展(第3.10节)。

Raft算法相关特性
图3.2的说明:
Raft算法的关键性质:
(1)Election Safety(Leader选举的安全性,所谓的安全性就是系统中不会发生不该发生的事情):在某一个特定Term(这里就叫任期吧)内,最多有一个Leader能够被选出(那么不该发生的事就是一个任期内有多个Leader被选出,在Raft算法中,这是不会发生的);
(2)Leader Append-Only(仅追加):一个Leader仅仅会在它自己的Log追加Entry,绝不会删除或者覆盖已有的Entry(这是Raft算法能够实现单向数据同步的保证,试想,如果Leader的Log内容可以随便的改动,Follower不敢从Leader同步,因为不知道同步过后会不会又变了。而且,这个属性的基础来自于Raft算法有一个保障,那就是当选的Leader的Log一定是最完整、最新的,详细算法会在后面内容中叙述并证明);
(3)Log Matching(Log匹配):如果某两个服务器节点中的Log Entry有相同的Term以及Index,那么这两个节点的Log在Index之前的所有Entry内容一定相同;
(4)Leader Completeness(Leader完整性):如果某个Log Entry已经在某个Term(任期)被commit,那么这个Log Entry一定会存在于以后所有任期的Leader的Log中;
(5)State Machine Safety(状态机安全性):如果某个服务器已经在其状态机中Apply某个Log Entry,那么其它的服务器绝不会在相同的Log Index上Apply其它的Log Entry。也就是说,在所有状态机的Log上,只要是相同的Index,其对应的Entry的内容一定是一样的。
image.png

图3-1给出了Raft算法中关键的元素、操作以及原则,因为整张图太大,下面切分这个大图为4个小图来说明。


image.png

图3-1 State(状态)
1.Persistent state on all servers(在所有服务器上持久化State)
(在回复RPC请求前更新本地持久化存储内容)

<center style="box-sizing: border-box; margin-top: 0px; margin-bottom: 0px; color: rgb(192, 192, 192); text-decoration: underline;">图3.2-2 RequestVote RPC</center>

image.png
  1. RequestVote请求,这是一个RPC请求

(candidate调用该请求来收集选票)

image.png

3.AppendEntries RPC,这是一个RPC请求,用于Leader向Followe同步log entry,Leader通过这个RPC请求要求Follower追加log entry以实现log的同步

(被Leader调用以用于进行log entry的备份,这个请求也会肩负心跳检查的功能)

为了说明prevLogIndex和prevLogTerm比较的方案,请看下图。

image.png

图中的Leader和Follower的任期都是3,Leader里面的log entry比Follower的新,所以Leader需要发送AppendEntries请求以使Follower同步这些log entry。这是,RPC请求内的prevLogIndex和prevLogTerm分别为i-1和3,当Follower接收到这个RPC请求时,其当前的log entry的index=i-1,任期为3,与RPC消息中的prevLogIndex和prevLogTerm匹配,那么Follower就可以使用entries[]里面的log entry来填充自己的i到n。如果Follower的最新的log entry的index(这里暂时成为FollowerIndex)不等于i-1,这里又分成两种情况,第一种,FollowerIndex<prevLogIndex,说明这个Follower的log还有缺失,那这个Follower会回复false,Leader会重新更新prevLogIndex、prevLogTerm以及entries[]并再次发起AppendEntries请求(后面的章节会详细介绍);第二章情况,FollowerIndex>prevLogIndex,说明Follower已经同步了prevLogIndex和prevLogTerm后面的log entry,但是,后面的log entry的内容是不是和RPC请求中相同?而且prevLogIndex和prevLogTerm这个log entry里面的内容是不是与Leader的相同?“这里的疑问等看完后面的内容再更新”

image.png
  1. Rules for Servers,集群中服务器需要遵守的规则

<< 上一章:Raft算法的目的
下一章:Raft算法基础 >>

上一篇下一篇

猜你喜欢

热点阅读