大数据基础(5) - Raft协议

1. 整体介绍

  与Paxos不同,在满足类似一致性功能的前提下,Raft一致性协议的主要目标有2个,1是可理解性,2是系统的可实现性。Raft对于每个技术细节都有清晰的界定和描述,这也便于更加明确的进行系统的实现。

2. Raft 协议主要实现思路

  Raft 协议为了实现上述2个目标,主要有以下2个思路:

  1. 将整个一致性协议划分成明确的3个子问题,分别是:领导者选举、Log复制与安全性。
  2. 将Paxos的P2P模式改造为Master-Slave模式。

3. 基本概念介绍

  为了后续更加深入的理解,先了解以下基本概念。

3.1 服务状态机

  • 在任意时刻,集群中的服务器只会处于3种状态之一:Leader、Follower和Candidate;
  • 正常状态下,集群中只有1个处于Leader状态的服务器充当领导者,负责响应所有客户端;
  • 其他服务器都处于Follower状态,被动接收RPC消息,不主动发任何消息;
  • Candidate状态是Follower状态服务器准备发起新的领导者选举前需要转换到的状态;

  状态转换图如下:

Raft状态转换图

3.2 任期(Term)

  Raft将整个系统执行时间划分为若干过不同时间间隔长度的时间片段构成的序列,每个片段成为1个Term,Term为递增数字。

  • 每个Term由选举(Election)开始,在这个时间内若干处于Candidate状态的服务器视图竞争新的领导者;
  • 如果某个服务器赢得了选举,则在这个Term接下来的时间里充当新的领导者;
  • 可能存在由于选票分流导致在某些Term内没有成功选举出新的领导者;
  • Raft协议可以保证在1个Term内最多会有1个服务器会被选举成新的领导者;

  Term序列图如下:

Term序列图

3.3 脑裂

  系统中同时有多余一个领导者,被称之为脑裂(brain split),这是非常严重的问题,会导致数据的覆盖丢失。

  Raft的以下两点保证了这个属性:

  1. 一个节点某一任期内最多只能投一票;
  2. 只有获得大多数投票的节点才会成为领导者;

3.4. Master-Slave模式

  前面有提到,Raft协议是将Paxos的P2P模式改造为Master-Slave模式,Paxos的复杂性一大部分原因是P2P模式造成的,多个并发进程间没有主次关系,具有同等地位,承担多种角色,Raft通过选举领导者,进行了模式转化,简化了一致性的维护问题,如果领导者失效,会重新选出新的领导者继续后续任务。

4. Raft的3个独立子问题

4.1 领导者选举(Leader Election)

  Raft的选举基于心跳机制,整个系统启动时所有服务器处于Follower状态,除非服务器接收到处于Leader或Candidate状态服务器发出的RPC命令,否则会一直维持之前的状态不变。

  Leader会周期性的向所有节点发送心跳包来维持自己的权威。如果Follower经过一个时间段(选举超时时间)没有接收到任何的心跳信息,可以认为领导者已经不复存在,触发新的Leader选举过程。

  选举前,准备以下事宜:

  1. Follower增加其Term编号,转入Candidate状态;
  2. 向所在集群内所有其他服务器发出RequestVote RPC消息;

  接下来会一直处于Candidate状态,等待以下情况发生:

  1. 赢得本次选举;
  2. 另外1个服务器S宣称并确认自己是新的领导者;
  3. 经过一定时间后,仍然没有新的领导者产生,进入下一个Term;

  下面对于以上3种情况,进行详细的解读

  • 情况1:如果Candidate接收到的大多数其他具有相同Term的服务器的投票,则赢得选举成为新的领导者,然后向其他服务器发送RPC心跳,宣布并维护其领导者地位。这里顺便说下,投票服务器智能将选票投给其中的一个选举者。

  • 情况2:Candidate在等待过程中可能会接收到新的RPC消息,这是另外一个服务器宣称自己是新的领导者而发出的。如果这个RPC里面的Term编号大于等于Candidate自身的Term编号,则Candidate承认这个新的领导者有效,自己转为Follower状态。否则Candidate拒绝承认新的领导者,并维持Candidate状态。

  • 情况3:如果出现平票的情况,大家都在等待,直到超时,然后重新发起选举。这样也延长了系统的不可用的时间,因此raft引入了领导者选举超时机制来尽量避免平票的情况,同时在leader-based共识算法中,节点的数目都是奇数个,也尽量保证了领导者的出现。

4.2 日志复制(Log Replication)

  所有的客户端请求都由领导者来负责响应。

  1. 领导者接收到客户端的操作命令后,将其作为新项目追加到Log尾部;
  2. 向集群内所有其他服务器发出AppendEntries RPC请求,引发其他服务器复制新的操作命令;
  3. 当其他服务器安全复制了新的操作命令后,领导者将这个操作命令应用到内部状态机,将执行结果返回给客户端;

  服务器的Log结构图如下:

服务器的Log结构图

  上图每个Log中包含2项内容:

  • 操作命令
  • Term编号:这是领导者接收到操作命令时的Term标识

  同时,还有一个全局索引来指示Log项目在Log中的顺序编号。

  领导者会决定哪些Log项目可以安全的应用到状态机上,应用到状态机上的项目被称为已经提交的项目。

  Raft保证了这些已提交项目的持久化存储以及让所有的服务器都按相同的顺序执行这些操作命令。

  Raft通过以下2个措施来保证一致性协议的安全要求:

  1. 不同服务器的Log中,如果2个Log项目具有相同的全局索引编号以及相同的Term编号,则这2个项目对应的操作命令也一定相同;
  2. 不同服务器的Log中,如果2个Log项目具有相同的全局索引编号以及相同的Term编号,那么Log中这个项目之前的所有前趋Log项目都完全相同;

4.3 安全性约束(Safety)

  虽然以上2个措施能够保证一般情况下Raft的正常运行,但无法做到完全的安全性保证,即无法保证每个状态机都按相同的顺序执行相同的操作命令。

  我们举例来说明,假设在领导者提交几个操作命令期间某个Follower处于失效状态,这个Follower回复后被选举成了新的领导者,这个时候新的领导者就会用自己的Log覆盖旧的领导者的Log信息,此时就无法达到安全性保证,旧的领导者已经将其新增的操作命令体现到了自己的状态机上,新的领导者并未存储这些操作命令,所以其他服务器也不可能应用这些操作序列,导致状态机出现不一致状态。

  为了达到真正的安全性,Raft增加了如下2个约束条件:

  1. 约束条件限制了哪些服务器可以被选举成为领导者,要求只有其Log包含了所有已经提交的操作命令的那些服务器才有权被选举成为新的领导者;
  2. 约束条件限制了哪些操作命令的提交可以被认为是真正的提交,对于新的领导者来说,只有它自己已经提交过当前Term的操作命令,才被认为是真正的提交;

  当然,Raft协议可能仍然存在特殊情况下安全性无法保证的情况,它依旧有能够进一步改善和完善的地方。


  参考文章

https://zhuanlan.zhihu.com/p/404786050
https://blog.csdn.net/yangmengjiao_/article/details/120191314
https://www.cnblogs.com/sfzlstudy/p/16015450.html
https://blog.csdn.net/joyblur/article/details/119323442
https://github.com/etcd-io/etcd/tree/main/raft

猜你喜欢

转载自blog.csdn.net/initiallht/article/details/124279998
今日推荐