分布式-Paxos以及Raft 共识算法

举报
object 发表于 2024/04/16 20:36:00 2024/04/16
【摘要】 共识算法共识算法是一种用于分布式系统中的算法,其目的是让不同的节点在没有中心化控制的情况下,达成一致的决策。这个决策可以是任何事情。在一个分布式系统中,每个节点都有自己的数据和状态,这些节点需要相互通信以达成共识。共识算法的作用就是让这些节点在达成共识时,保持一致性和正确性。这对于构建高可用性、高性能、可拓展性的分布式系统至关重要。适用于实际系统的共识算法通常具有以下特性:安全。确保在非拜占...

共识算法

共识算法是一种用于分布式系统中的算法,其目的是让不同的节点在没有中心化控制的情况下,达成一致的决策。这个决策可以是任何事情。

在一个分布式系统中,每个节点都有自己的数据和状态,这些节点需要相互通信以达成共识。共识算法的作用就是让这些节点在达成共识时,保持一致性和正确性。

这对于构建高可用性、高性能、可拓展性的分布式系统至关重要。


适用于实际系统的共识算法通常具有以下特性:

  • 安全。确保在非拜占庭条件下的安全性,包括网络延迟、分区、包丢失、复制和重新排序
  • 高可用。只要大多数服务器是可操作的,并可以相互通信,那么这些服务器就可以看做完全功能可用。
  • 一致性不依赖时序。错误的时钟和极端的消息延迟,在最坏的情况下也只造成可用性问题,而不会产生一致性问题。
  • 在集群中大多数服务器响应,命令就可以完成,不会被少数运行缓慢的服务器来影响整体性能

Paxos算法

Paxos是第一个被证明完备的共识算法(前提是不存在拜占庭将军问题,即没有恶意节点)

pax算法主要包含

  • Basic Paxos算法:描述的是多节点之间如何就某个值(提案)达成共识
  • Multi-Paxos思想:描述的是执行多个Basic Paxos示例,就一系列值达成共识。


Basic Paxos算法的3个重要角色

  • 提议者(Proposer):也称协调者(coordinator),提议者负责接收客户端的请求并发起提案。提案信息包括编号(Proposal ID)和提议的值(Value)
  • 接受者(Acceptor):也可以叫做投票员(voter),负责对提议者的提案进行投票,同时需要记住自己的投票历史;
  • 学习者(Learner):如果有超过半数接受者就某个提议达成了共识,那么学习者就需要接受这个提议,并就该提议作出运算,然后将运算结果返回给客户端。


Raft算法

由于Paxos算法在国际上被公认难以理解和实现,不断有人简化,诞生了比Paxos算法更易理解的和实现的共识算法Raft算法。

Raft节点类型

一个Raft集群包括若干服务器,以典型的5服务器集群举例。在任意的时间,每个服务器一定会处于以下三个状态中的一个:

  • Leader:负责发起心跳,响应客户端,创建日志,同步日志。
  • Candidate: Leader选举过程中的临时角色,由Follower转化而来,发起投票参与竞选。
  • Follower: 接受Leader的心跳和日志同步数据,投票给Candidate。

正常的情况下,只有一个服务器是Leader,剩下的服务器是Follower。Follower是被动的,他们不会发送任何请求,只是响应来自Leader和Candidate的请求

Raft 任期

Raft把时间切割为任意长度的任期(Term),每个Term都是一个连续递增的编号,采用连续的整数来表示。每个任期都由一次选举开始,每一轮选举都是一个Term任期,若选举失败则这个任期内没有Leader。如果选举出了Leader则这个任期内由Leader负责集群状态管理,在一个Term中只能产生一个Leader。

Term的变化流程:Raft开始时所有的Follower的Term为1,其中一个Follower的超时时间到期后转换为Candidate,Term加1(这时为2),然后开始选举,这时候有几种情况会使Term发生改变:

  • 如果当前Term为2的任期内没有选举出Leader或出现异常,则Term递增,开始新一任期选择。 (平票或出问题了)
  • 当这轮Term为2的周期选举出Leader后,过一段时间Leader挂掉了,Follower转为Candidate,Term递增(新Leader挂掉,新的任期开始)
  • 当Leader或Candidate发现自己的Term比别的Follower小,Leader或Candidate将转为Follower,Term递增(之前挂掉Leader重新连上了)
  • 当Follower的Term比别的Term小,follower也将更新Term保持与其他Follower一致(之前挂掉的Follower重新连上了,且有新的Leader出现)

每次Term的递增豆浆发生新一轮选举,Raft保证一个Term任期内只有一个Leader,在Raft正常运转中所有的节点的Term都是一致的,如果节点不发生故障一个Term会一直保持下去,当节点收到的请求中Term比当前Term小时则拒绝该请求。

日志

  • entry: 每一个时间称为entry,只有Leader可以创建entry。entry的内容<term,index,cmd>其中cmd是可以应用到状态机的操作。
  • log: 由entry构成的数据组,每一个entry都有一个表明自己在log中的index。只有Leader才可以改变其他节点的log。entry总是先被Leader添加到自己的log数组中,然后再发起共识请求,获得同意后才会被Leader提交给状态机。Follower只能从Leader获取新日志和当前的commitIndex,然后把对应的entry应用到自己的状态机中。

领导人选举

Raft使用心跳机制来触发Leader选举。

Leader会向所有的Follower周期性发送心跳保证自己的Leader地位。如果Follower一个周期内没收到心跳,则选举超时,开始进行选举新的Leader。Follower会自增自己的term号并且转换为Candidate,然后会向所有节点发起请求,Candidate的状态会持续直到:

  • 自己赢得选举
  • 其他节点赢得选举
  • 无节点赢得选举

赢的条件为: 一个Candidate在一个任期内收到了来自集群内 的多数选票(N/2+1)。

当Candidate选举的时候,可能会收到来自Leader的心跳,此时分两种情况:

  • 该Leader的term号大于等于自己的term号。对方已成为Leader,自己退回Follower
  • 该Leader的term号小于自己的term号。那么拒绝请求并让该节点更新term。

由于可能存在多位Candidate的情况,如果仅依靠投票,可能会出现无限重复的情况。

Raft使用了随机的选举超时时间来避免。每个Candidate在发起选举后,都会随机化一个新的选举超时时间,这种机制使得各个服务器能够分散开,在大多数情况下只有一个服务器会率先超时,他会在其他服务器超时之前赢得选举。

Raft日志复制

一旦选出了Leader,它就开始接受客户端请求。每一个客户端的请求都包含一条需要被复制状态机的命令

Leader收到客户端请求后,会先生成一个entry。包含<index,term,cmd>,再将这个entry添加到自己的日志末尾后,向所有的节点广播该entry,要求其他服务器复制这条entry。

如果Follower接受该entry,则entry添加到自己的日志后面,同时返回给Leader同意。

如果Leader收到了多数的成功响应,Leader会将这个entry应用到自己的状态机中,之后可以称这个entry是committed的,并且向客户端返回执行结果。

raft保证以下两个性质:

  • 在两个日志里,有两个entry拥有相同的index和term,那么他们一定有相同的cmd
  • 在两个日志里,有两个entry拥有相同的index和term,那么他们前面的entry也一定相同。

第一条通过仅有一个Leader保证,第二个需要一致性检查来保证。

一般情况,Leader和Follower的日志是一致的,但由于Leader崩溃,导致了日志不一样,Leader会强制Follower复制自己的日志。Leader会进行比对,找到日志一致的地方,然后删除Follower之后的日志,把之后的日志发给Follower。

  • 具体实现步骤为。Leader给每一个Follower维护了一个nextINdex。它表示将要发送给Follower的下一条日志条目的索引。当一个Leader选举成功时,它会将nextIndex初始化为它最新的日志条目索引数+1。如果一个Follower的日志和Leader不一致,则AppendEntries一致性检查会在下一次AppendEntries RPC时返回失败。失败之后,Leader会将nextIndex递减然后重试AppendEntries RPC。最终一致。这时Follower会移除掉冲突日志,并且添加Leader的日志条目,这样就保证了Leader和Follower的日志一致性,这样会持续到当前任期结束。

安全性

选举限制

Leader需要保证自己存储全部已经提交给日志条目,这样才可以使日志条目只有一个流向。Leader到Follower.

每个Candidate发送RequestVoteRPC时,都会带上最后一个entry的信息,所有节点收到投票时,会对该entry进行比较,如果发现自己的更新,则拒绝投票给该Candidate。

判断日志新旧的方式:如果两个日志的term不同,term大的更新;如果term相同,更长的index更新。

节点崩溃

如果Leader崩溃,集群中的节点在electTimeout时间内没有收到Leader的心跳信息就会触发新一轮的选举,在选举期间整个集群对外是不可用的。

如果Follower和Candidate崩溃,处理方式会简单很多。之后发送给它的RquestVoteRPC和AppendEntriesRPC会失败。由于raft的所有请求都是幂等的,所以失败的话会无限重试。如果崩溃回复后,就可以收到新的请求,然后选择追加或者拒绝entry。

时间与可用性

raft的要求之一就是安全性不依赖于时间:系统不能仅因为一些事件发生的比预想快或者慢一些就产生错误。为了保证上诉要求,最好能满足以下的时间允许:

broadcastTime << electionTimeout << MTBF

  • broadcastTime:向其他节点并发发送消息的平均响应时间;
  • electionTimeout:选举超时时间;
  • MTBF(mean time between failures):单台机器的平均健康时间;


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。