Raft 分布式系统 一致性协议

Raft

Raft is a consensus algorithm that is designed to be easy to understand. It’s equivalent to Paxos in fault-tolerance and performance. The difference is that it’s decomposed into relatively independent subproblems, and it cleanly addresses all major pieces needed for practical systems. We hope Raft will make consensus available to a wider audience, and that this wider audience will be able to develop a variety of higher quality consensus-based systems than are available today.

Raft类似Paxos,是一个分布式的一致性的协议,而且更容易理解。

Raft一致性算法

Raft协议主要使用了两种策略。一是将复杂问题进行分解,在Raft协议中,一致性问题被分解为:leader election、log replication、safety三个简单问题;二是减少状态空间中的状态数目。下面我们详细看一下Raft协议是怎样设计的。

在Raft体系中,有一个强leader,由它全权负责接收客户端的请求命令,并将命令作为日志条目赋值给其他服务器,在确认安全的时候,将日志命令提交执行。当leader故障时,会选举产生一个新的leader。在强leader的帮助下,Raft将一致性问题分解为了三个子问题:

  • leader选举:当已有的leader故障时必须选出一个新的leader
  • 日志复制:leader接受来自客户端的命令,记录为日志,并复制给集群中的其他服务器,并强制其他节点的日志与leader保持一致。
  • 安全safety措施:通过一些措施确保系统的安全性,如确保所有状态机按照相同顺序执行相同命令的措施。
基本概念

一个Raft集群拥有多个服务器,典型值是5,这样可以容忍两台服务器出现故障。服务器可能会处于如下三种角色:leader、candidate、follower,正常运行的情况下,会有一个leader,其他全为follower,follower只会响应leader和candidate的请求,而客户端的请求则全部由leader处理,即使有客户端请求了一个follower也会将请求重定向到leader。candidate代表候选人,出现在选举leader阶段,选举成功后candidate将会成为新的leader。

从状态转换关系图中可以看出,集群刚启动时,所有节点都是follower,之后在time out信号的驱使下,follower会转变成candidate去拉取选票,获得大多数选票后就会成为leader,这时候如果其他候选人发现了新的leader已经诞生,就会自动转变为follower;而如果另一个time out信号发出时,还没有选举出leader,将会重新开始一次新的选举。可见,time out信号是促使角色转换得关键因素,类似于操作系统中得中断信号。

在Raft协议中,将时间分成了一些任意长度的时间片,称为term,term使用连续递增的编号的进行识别。每一个term都从新的选举开始,candidate们会努力争取称为leader。一旦获胜,它就会在剩余的term时间内保持leader状态,在某些情况下(如term3)选票可能被多个candidate瓜分,形不成多数派,因此term可能直至结束都没有leader,下一个term很快就会到来重新发起选举。

term也起到了系统中逻辑时钟的作用,每一个server都存储了当前term编号,在server之间进行交流的时候就会带有该编号,如果一个server的编号小于另一个的,那么它会将自己的编号更新为较大的那一个;如果leader或者candidate发现自己的编号不是最新的了,就会自动转变为follower;如果接收到的请求的term编号小于自己的当前term将会拒绝执行。

server之间的交流是通过RPC进行的。只需要实现两种RPC就能构建一个基本的Raft集群:

  • RequestVote RPC:它由选举过程中的candidate发起,用于拉取选票。
  • AppendEntries RPC:它由leader发起,用于复制日志或者发送心跳信号。

Raft通过心跳机制发起leader选举。节点都是从follower状态开始的,如果收到了来自leader或candidate的RPC,那它就保持follower状态,避免争抢成为candidate。Leader会发送空的AppendEntries RPC作为心跳信号来确立自己的地位,如果follower一段时间(election timeout)没有收到心跳,它就会认为leader已经挂了,发起新的一轮选举。

选举发起后,一个follower会增加自己的当前term编号并转变为candidate。它会首先投自己一票,然后向其他所有节点并行发起RequestVote RPC,之后candidate状态将可能发生如下三种变化:

  • 赢得选举,称为leader: 如果它在一个term内收到了大多数的选票,将会在接下的剩余term时间内称为leader,然后就可以通过发送心跳确立自己的地位。(每一个server在一个term内只能投一张选票,并且按照先到先得的原则投出)
  • 其他server称为leader:在等待投票时,可能会收到其他server发出AppendEntries RPC心跳信号,说明其他leader已经产生了。这时通过比较自己的term编号和RPC过来的term编号,如果比对方大,说明leader的term过期了,就会拒绝该RPC,并继续保持候选人身份; 如果对方编号不比自己小,则承认对方的地位,转为follower
  • 选票被瓜分,选举失败: 如果没有candidate获取大多数选票, 则没有leader产生, candidate们等待超时后发起另一轮选举. 为了防止下一次选票还被瓜分,必须采取一些额外的措施, raft采用随机election timeout的机制防止选票被持续瓜分.通过将timeout随机设为一段区间上的某个值, 因此很大概率会有某个candidate率先超时然后赢得大部分选票
日志复制过程

一旦leader被选举成功,就可以对客户端提供服务了。客户端提交每一条命令都会被按顺序记录到leader的日志中,每一条命令都包含term编号和顺序索引,然后向其他节点并行发送AppendEntries RPC用以复制命令(如果命令丢失会不断重发),当复制成功也就是大多数节点成功复制后,leader就会提交命令,即执行该命令并且将执行结果返回客户端,raft保证已经提交的命令最终也会被其他节点成功执行。leader会保存有当前已经提交的最高日志编号。顺序性确保了相同日志索引处的命令是相同的,而且之前的命令也是相同的。当发送AppendEntries RPC时,会包含leader上一条刚处理过的命令,接收节点如果发现上一条命令不匹配,就会拒绝执行。

在Raft中,leader通过强制follower复制自己的日志来解决上述日志不一致的情形,那么冲突的日志将会被重写。为了让日志一致,先找到最新的一致的那条日志(如f中索引为3的日志条目),然后把follower之后的日志全部删除,leader再把自己在那之后的日志一股脑推送给follower,这样就实现了一致。而寻找该条日志,可以通过AppendEntries RPC,该RPC中包含着下一次要执行的命令索引,如果能和follower的当前索引对上,那就执行,否则拒绝,然后leader将会逐次递减索引,直到找到相同的那条日志。

宏观结构

首先我们假设有三个 RaftNode,每个 RaftNode 都会开设一个端口,这个端口的作用就是接受客户端的(Get/Set)请求以及其它 RaftNode 的 RPC 请求。这里需要说明的是多数著名开源项目一般会选择两个端口,一个面向客户端,一个面向 RPC,好处是可以选择不同的 IP 地址,客户端端口可以面向外网,而 RPC 则是安全的内网通信。作者选择了一个端口是因为只用于内网,在实现上也会简单不少。

当选 Leader 的条件

并不是任意一个节点都可以变成 Leader。如果要当 Leader,这个节点包含的日志必须最全。Candidate 通过 RequestVote 消息拉票的时候,需要携带当前日志列表的 lastLogIndex 和相应日志的 term 值(尾部日志的 term 和 index )。 其它节点需要和这两个值进行匹配,凡是没自己新的拉票请求都拒绝。

日志压缩

随着日志大小的增长,会占用更多的内存空间,处理起来也会耗费更多的时间,对系统的可用性造成影响,因此必须想办法压缩日志大小。Snapshotting是最简单的压缩方法,系统的全部状态会写入一个snapshot保存起来,然后丢弃截止到snapshot时间点之前的所有日志。

文献

https://raft.github.io

https://raft.github.io/raft.pdf

http://verdi.uwplse.org

https://www.cl.cam.ac.uk/~ms705/pub/papers/2015-osr-raft.pdf

有时候看博客总是觉得没说清楚呢??但是看源码感觉还是无能为力啊。。。下次继续看看

发布了156 篇原创文章 · 获赞 7 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/LU_ZHAO/article/details/104934220
今日推荐