Raft论文总结

raft论文总结

为什么需要对大规模的数据集进行存储和计算?

当用户量扩大,请求响应和存储安全需求越来越高,单一服务器已经无法满足实际的使用情况。

解决方法有二:

1.换一台更好的服务器
2.多几台服务器一起用

从利润和技术的角度出发,后者比前者更容易实现。多台服务器一起来处理用户的请求,保存用户的信息。用户的每一个请求落实到数据库中就是一次增删改查,抽象出来就是一条对数据操作的指令。而将这些指令操作进行提交运行并存储每一条指令的结果,就是服务器的基本功能。但是服务器很可能同时接收到多条指令,收到一条就处理一条是一种算力应用低下的方法。为了充分利用算力资源,服务器可以存储多条指令然后统一处理,提升响应速度。

raft是什么

raft是组织机器使其状态最终一致并允许局部失败的一致性算法,用于管理集群中的日志信息。

什么是一致性算法?

一致性算法的目标是保证集群上所有节点的状态一致性,节点要执行写指令时会改变节点的状态,因此为了保证集群各个节点状态的一致性,就必须将写指令同步给所有的节点。但由于网络延迟要慢于内存操作,因此我们不要求同步命令被立即执行,而是仅仅保证所有的写指令在所有的节点上按同样的顺序最终被执行。

什么是日志?

日志就是客户端发来的执行指令,有读指令也有写指令。为了保证所有的写指令在所有的节点上按同样的顺序最终被执行,raft仅仅允许一个节点处理写命令,并且所有节点维护一份顺序一致的日志。每个节点上的状态机按照自己的节奏,逐跳应用日志上的写命令来变更状态。

为什么说raft好?

为了实现上文提到的最终一致性,需要对网络进行约束,即:

  1. 在非受信网络中出现网络问题时需要保证数据正确
  2. 集群中正确响应客户端的前提是大部分节点可以互相保持通信
  3. 一致性不能依靠时间约束
  4. 请求响应不能受限于集群中最慢的节点

raft为这些约束提出了可行解

初始化的时候有一个领导者节点,该节点和其他节点的区别在于,任意节点可以处理读请求而只有领导者节点能处理写请求。当写请求到来时,领导者先进行日志处理,然后负责同步日志到其他跟随者。被同步的跟随者会返回同步结果,只有半数以上的节点返回同步成功,领导者才会提交日志。日志最终由领导者按先后顺序应用于状态机,其他跟随者在交互过程中也会收到提交的指令,并将日志应用到各自的状态机。领导者崩溃之后,集群中其他节点会推举出新的领导者。有节点退出或有新节点加入时,集群的配置信息会改变,改变后的配置信息会同步到整个集群。

为什么说raft是安全的?

1.选举安全:同一任期内只有一个Leader被选出来

2.只有leader能添加新日志:leader只会添加而不会修改或者删除日志条目

3.日志匹配:如果两个节点的日志中包含具有相同任期和索引的条目,那么这两个日志从开始到前文提到的日志下标之间的所有条目都是相同的。

4.领导者完备性:一旦日志条目在当前任期被提交了,那么之后出现的所有领导者日志中都会有该已提交的日志条目。

5.状态机安全:如果服务器已将给定索引条目应用于状态机,则其他服务器不会在同一索引下应用不同的日志条目。

raft集群如何工作的?

请添加图片描述

1.client发送请求给server进行日志写入

2.接收请求的server会通过共识模块将日志写入到其他的server上

3.状态机处理命令序列,以确保它们有相同的输出

服务器三种状态

变化流程:

请添加图片描述

数据结构

什么是RPC?

全名:remote procedure calls

共识算法需要三种RPC:RequestVote、AppendEntries和用于传递快照的RPC

所有的RPC都是并行执行的

如何处理日志?

请添加图片描述

1.客户端发来请求,集群内任意非Leader节点接收后都会将请求重定向到leader节点。

2.Leader节点在接收到来自客户端的请求后,将请求按照顺序加入到log中 。

3.如果leader节点发现last log index ≥ 跟随者的nextIndex,就会从该跟随者的nextIndex开始发送rpc。

3.跟随者接收到leader节点rpc后,首先会通过参数prevLogTerm看任期是否正确,再通过参数prevLogIndex看前一个Log是否正确 ,然后将新的日志写入到当前的list中,并返回ack ,ACK包含参数term(这个term是跟随者的当前任期,为了让leader去更新自己的)和success(如果prevLogTerm和prevLogIndex匹配的话)。

4.leader在接收到follower回复后更新本地matchIndex和nextIndex,对应每个节点的匹配日志和下一次要发送给该节点的日志。(同时发送多个,rpc中有专门的参数entries[]);若失败则减少nextIndex的值然后重试,这里对应迭代解决冲突的方法。即找到follower和leader匹配的最后一个日志,删除follower该匹配日志之后的所有日志,再由leader重新同步。

5.在leader收到半数以上节点ack后,判定该日志已经成功同步到集群中

6.对于已经在集群中同步过的日志,将会被设置为commit 。这个commit指令会同步到其他节点中,每次复制Log的时候rpc都会带有参数leaderCommit来标识leader的commitindex。

问题1:同步时follower日志不对咋办

这个问题不会出现,日志复制的完全匹配证明过程:

因为集群任意时刻最多只有一个Leader。该leader不会删除或覆盖自己的日志,且在一个任期内只会在同一个索引处写入一次日志,日志一旦写入就不允许修改。

因此,只要日志集合对应任期和索引相同,那么在任何已经同步了该日志集合的节点上,该日志集合都是相同的

因为跟随者每次只会从leader的preLog处追加日志,且日志出现不匹配时会从leader的nextindex-1处迭代重试匹配,匹配到相同的日志时重新从leader处拉取日志。

因此一旦跟随者和leader在preLog出匹配,那么值钱的所有日志都是匹配的

问题2:发送失败,丢包,延迟怎么办

follower返回失败信息的场景如下:

1.跟随者收到了过时的任期消息

2.跟随者日志列表中不包含与PrevLogTerm匹配的PrevLogIndex,也就是说来的不是我想要的

3.条目冲突,例如相同的索引不同的任期。(这个时候就需要迭代删除已存在的条目直到与leader的条目匹配)

4.收到的rpc中没有包含新的条目

5.若leaderCommit比更随着的commitIndex大,则将自身commitIndex设置为leaderCommit和最新条目中小的那个

由于同步的方式是使用心跳包和NextLog,因此发送失败时会重新从NextLog中读取发送位置不断发送 。小延迟不影响同步,因为每个log都有严格的顺序,是用来确保数据一致性的关键。大延迟只能出现在节点断开连接或者集群发生脑裂。这个时候会标记跟随者下线或者重选leader,对待前者leader会以幂等的方式发送心跳,等待其重新连接之后再次执行同步;对待后者会有选举超时的timer,并以此重新进行选举。

如何选举leader?

请添加图片描述

以有五个节点的集群为例

集群的具体工作流程是从选举开始的
请添加图片描述

解释:

选举这里是一段时间的工作出现问题leader没了选举一段时间工作崩溃选举失败再选…
任期的作用:

任期就像一个逻辑锁,它允许服务器发现过时的信息,例如过时的领导者。

选举流程:

1.follower在一定时间内没有接收到leader的心跳包则发起选举,角色变为候选人

2.候选人对自己原先的任期值加1(这里就是状态的转变,从跟随者转变为候选人状态)以便与前任作区分,并且会将选举计时器重置。结束候选人状态的场景有三:

​ a.赢得选举

​ b.其他服务器抢先成为Leader,也就是收到了任期至少相当于候选人当前任期的RPC,此时候选人重新变回跟随者。但是不满足任期条件的RPC会被拒绝,候选者继续自己的竞选流程。

​ c.选举超时

3.候选人当收到超过半数的返回时开始递交选举rpc

4.选举rpc里会有候选人的ID、最新的日志对应的任期和最新log情况

5.投票环节就是候选人将自己的情况发给follower,目的是将follower本着先到先服务的精神,将 voteFor参数变成候选人的ID。

6.每个follower都只有一票,选择候选人之后会发送Ack确认。候选人自己的票当然是投给自己的

7.当候选人收集到超过半数的节点投票后自动晋升为leader,首先会发送空的AppendEntries RPCs给各个服务器,并且在空闲的时候重复此操作以防选举超时。

问题1:候选人都投票给自己不给别人咋办

这种情况发生在大家都变成候选人,然后都投自己,导致票数不够。选举采用的机制是,在一定时间范围内的随机时间点发送rpc给其他节点。因为节点接收到其他选举人的rpc时间不同,总会有先来后到。一旦先来的rpc通过的筛选被节点推举为新的Leader那么久不存在僵持的问题。

问题2:follower怎么选择候选人

首先判断候选人的任期是否是最新的,一旦有任期最新的rpc传来,它就会抛弃旧的leader。其次,要比较候选节点的日志是否比自己更新,这样有利于选出日志最新的节点作为新leader

问题3:作为原先的follower,候选人怎么知道当前集群有多少节点

由于有集群配置的存在,当leader管理集群的时候也会同步配置信息告知其他节点当前集群节点数量。这样一来,当有新的节点加入集群时,也需要更新配置信息。

问题4:选举失败的场景

1.跟随者的当前任期大于选举rpc中的任期

2.跟随者自身属性voteFor不是空且不是当前收到的rpc中的选举者id,这意味着该跟随者已经投过票,且不是当前发起请求的候选人

3.候选人的日志落后于跟随者,这点可以从RPC中的LastLogIndex得出

4.在选举过程中收到了AppendEntries RPC,说明已经有leader被选出来了

5.候选人的选举计时器超时,则本轮选举失败,开始新的选举轮次

如何保障被选出的leader是有效的?

场景出现在leader反复选举时,即使日志条目被半数以上的节点复制了,但是不代表条目已经被提交到集群。如图:

请添加图片描述

这张图想要表达的意思是,当领导者不断的切换时,由于每一任领导者都没有提交任期内的日志条目而是单纯的将日志复制到大多数节点,导致了新的领导者无法单纯依靠之前任期的日志条目判断它当前的提交条件。

(a)时刻S1是leader,产生了在2号位置的日志条目(任期:2,值:2),然后复制到S2节点后就发送了宕机。

(b)时刻S5收到S3/S4的投票被选为leader,产生了在3号位置的日志条目(任期:3,值:3)。但S5没有来得及做任何复制操作,它就宕机了。

(c)时刻S1重启,获得了除S5外其他节点的投票,被选为第4任期的leader,并继续向S3复制2号位置的日志。此时,2号位置的日志在大多数节点上完成了复制。

(d)时刻S1宕机,S5再次被选为领导人。然后S5用自己的本地日志覆盖了所有节点上的日志。

这个例子说明,只有提交到集群的日志才无法被修改,未提交的日志存在被迭代重写的可能。

解决方法:新领导者上任时,在接收到客户端写入命令前,先提交一个no-op(空命令)。该命令携带自己的任期号,并被复制到大多数集群节点上。就像(e)展示的那样,S1宕机前(也就是前面的(c)时刻)将任期为4的日志复制到大多数节点上,这样S5就不会赢的选举。

以上的例子体现了选举可能产生的问题和解决方法,那么为什么这个解决方法是有效的呢?具体证明如下:

假设A是上一个任期最后的已提交日志,B为当前任期的leader。此时,A作为已提交日志必然被同步到了半数以上的节点中。B作为半数以上节点选出来的leader,其选民的本地日志中必然包括A。又因为B被选举为leader的前提是它的日志比给它投票的选民都要新,因此B必然包含日志A。又因为日志的完全匹配,B包含A意味着B包含比A小的所有日志。

因为最新添加的日志索引要大于已提交的索引,且raft保证已提交的日志在集群所有节点上顺序一致,因此被应用于状态机的日志必然在所有节点上顺序一致。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值