分布式共识算法(1)- Basic Paxos

前言

这里说的分布式系统是指用集群部署方式提供统一服务的架构,并不是指微服务或者大型电商这种拥有多种功能不同节点构成的系统,这类多节点、多服务的系统主要是为了把大型系统拆分成多个小系统方便维护,可以进行局部升级。而集群部署的分布式系统的多个节点的功能相同、数据相同,是为了提高可用性。从概率角度描述,假设一个节点的故障率是P,则单点系统的可用性为1-P。假设有N个节点同时提供服务,每个节点的故障率都是P,则整个集群的可用性为1-P^N,显然N越大,可用性越高。
节点数越多,维持节点间数据一致性越困难,通常可分为两种模式:以数据同步为方式的状态转移和以操作同步为方式的操作转移。将某一个节点的某个时刻的数据视为一个状态,通过数据复制的方式同步到其他节点,就是状态转移操作转移则是将节点的数据视为状态机,通过某些操作如增删改引起了状态变化,只需要将这些操作同步到其他节点并执行,其他节点的数据也能转移到同样的状态,目前主流的分布式系统均以操作转移方式进行数据同步。而且分布式环境下,网络分区不可避免,为了保证可用性,通常采用“少数服从多数”原则,只要大部分节点完成了状态变换,就认为系统实现了数据同步,就可以对外提供服务,而少部分节点的数据不一致则需要系统自行处理。
这个让系统各节点容忍网络分区、节点崩溃、执行速度不一致等因素,最终呈现出数据整体一致的过程,就称为协商共识(Consensus)。而我们常说的一致性(Consistency)是指数据间的差异。一致性是我们追求的目标,例如数据的ACID原则中,通过AID来保证C。在分布式系统中,通过协商共识的方法,来保证节点间的一致性。

Paxos

Paxos是分布式系统中最重要的基础共识算法,最早于1990年发表,在2006年广为人知,其后的Raft、ZAB等算法均在Paxos基础上发展而来。Paxos实际包含两部分:Basic Paxos 和 Multi Paxos。Basic Paxos可以就某一个问题达成共识,这里是说,整个分布式系统只能就一个问题达成共识,它不能处理更多问题,共识达成之后也不能再修改,典型的如三军问题(指挥部通过通信兵和三支军队协商何时发起攻击问题,非拜占庭问题,即消息不会被篡改)。显然Basic Paxos应用场景非常有限,Multi Paxos 则是在 Basic Paxos 算法基础上用来解决多个问题共识问题,也就是我们现在比较熟悉的zookeeper、etcd等分布式协调系统可以提供基于K-V的共识服务。

Basic Paxos

Basic Paxos将系统中的节点分为三类角色:

  • Proposer,提案节点。其可以向所有决策节点提出一个提案(Proposal),每个提案都携带一个ID和value,每个节点的ID是自增的,通常使用时间戳和节点Id组合,value则是针对目标问题的值。
  • Acceptor,决策节点。其收到提案节点的提案,针对某提案,其可以回应提案是否可被投票、是否可被接受。超过大多数(事先配置)的决策节点认为某提案可被投票,则该提案进入下一环节:是否可被接受,否则将被丢弃。超过大多数的决策节点认为某提案可被接受,则该提案被Accept,这意味着该提案将会被正确存储在系统中,并最终同步到所有节点。
  • Learner,记录节点。不参与提案、投票,单纯从提案节点、决策节点同步已经被Accept的提案。

在部署环境中,某个节点可以既是提案节点,又是决策节点,显然,为了满足大多数这个条件,决策节点数量应该为奇数,并且在系统启动时,每个节点都应该知道系统中所有的提案、决策节点的个数、地址等信息。
下面以三军问题为例,描述 Basic Paxos算法工作流程,背景设定如下,有三支军队A\B\C处于某敌军城池三面,他们相互知道对方的位置,准备通过通信兵商议发起进攻时间,但敌军会攻击通信兵,因此传递的消息可能会延迟、丢失,但只要两支军队同时进攻,就能攻破城池。这个案例中,三支军队的将军既是提案节点,又是决策节点,军队的各下级军官则是记录节点。协商分两个阶段:召开讨论会议、确定进攻时间。
所谓召开讨论会议,是指某军发出召开进攻时间讨论会议通知(Prepare请求),只有两支以上军队同意讨论(包括自己),才能进行下一步,要求各军接受自己设定的进攻时间,称为Accept请求。

接收到Prepare请求

当某军接收到一个讨论会议请求时,有四种响应情况:
1、这是自己收到的第一个讨论会议请求,决定参加。
2、自己已经答应参加另一个讨论会议,但该请求时间是最新的,决定不参加原来那个会议,转而参加最新的会议。
3、自己已经答应参加另一个讨论会议,且会议时间比该请求更新,决定仍然参加原来会议,忽略本次请求。
4、自己已经通过某次会议确定了进攻时间,直接返回会议代号和攻击时间(ID,Value)。
针对上述4中回应,发出Prepare请求的某军应对如下:
回应1:已经有2支军队参加讨论会议,自己已经是主导方,直接发出确定进攻时间请求,要求参会各军接受。
回应2:处理同回应1
回应3:参与会议的军队数量不足,会议召开失败,此时有两种应对:放弃,再次发起召开会议请求。
回应4:说明另外两种军队已经就进攻时间达成了一致,我军应该跟随,于是在本军中广播进攻时间,并再次传递到另外两军。

接收到Accept请求

当某军接收到一个确定进攻时间请求时,有三种响应情况:
1、自己从未接收到任何请求,即未收到参加会议邀请,这个确定进攻时间请求可能是别人已经达成的共识,我应该跟随,于是返回接受响应,即Accepted响应(ID,value),并通知所有军官。
2、自己已经接到了参加会议的邀请并承诺参加,但此时的【确定进攻时间请求】的发出时间早于会议发起时间,这意味着 进攻时间可能会在 下一次会议中修改,因此我将不会接受此【进攻时间请求】;
3、自己已经接到了参加会议的邀请并承诺参加,但此时的【确定进攻时间请求】的发出时间晚于会议发起时间,这意味着 最早我决定参加的那个会议因为某些原因未能举办,但有另外一个更近的会议已经达成了一个共识,因此我将会接受此【进攻时间请求】,发送Accepted响应,并广播全军。

示例

Case1,只有一个军队发起的正常流case:

假设T1时刻A军将军发起提案:我们来讨论下进攻时间,并将T1.A作为提案ID,由通信兵传输给其他两个军队,称为广播请求Prepare(T1.A)。
B\C两军接受到提案,由于他们之前并未收到任何关于进攻时间的讨论,因此他们决定同意将军A的提案,答应开始讨论,并通过通信兵回应,称为Promise(T1.A,null)响应。其中null表示自己还没有确定进攻时间,可以参加讨论。
将军A接受到同意讨论回应,于是发表自己的进攻时间:决定于午夜三刻进攻,此消息和提案ID一起再次传递给B\C两军。
B、C领军接收到消息,由于自己之前已经同意参加了T1.A的讨论会议,此时收到T1.A会议的结论,因此同意了“午夜三刻”这个值,回复Accept,并将此值在自己军内广泛传播,所有各级军官都认为在午夜三刻发起进攻。

Case2,两军已达成一致,另外一军不知情仍然发起流程:

A军发出讨论提案,使用T1.A作为提案ID,传递给BC两军,但只有B军接收并最终Accept,派往C军的通信兵被拦截,C军未收到提案信息。
由于三军中已有A\B两军就进攻时间达成一致,因此他们会在午夜三刻发起进攻,全军戒备,不会再更改、丢失。
C军未接收到任何消息,C军在T2时刻也发起讨论进攻时间提案,T2>T1,使用T2.C作为提案ID,传递给A\B两军,无论是A或B先接收到C军的提案,其都会返回(T1.A,“午夜三刻”)到C军,表示就“进攻时间”这个问题已经达成了一致,C军接收到返回后,认可“午夜三刻”这个时间并广播全军,同时将(T1.A,“午夜三刻”)再次广播给A\B两军,称为Accept请求。
A\B两军由于已经Accept了T1.A提案的值,将会忽略C军的Accept请求。

Case3,两军先后发起,但到达时间相反:

A军于T1时刻发出的讨论进攻时间的提案,由于敌军扫荡,通信兵被迫潜伏一天。
C军于T2时刻发出的讨论进攻时间的提案,通信兵顺利抵达A\B两军,B军回复同意C军的召回会议请求。但此时A军的通信兵到达,其携带提案T1.A,由于B军已经同意提案T2.C,因此其将会忽略这个迟来的T1.A提案,A军由于接受不到回应,则表明它未能召开会议

完整请求流程如下图所示:
在这里插入图片描述

总结

从上述三军问题的决策过程,我们可以总结出Basic Paxos算法的基本规则:
1、决策者记录自己已经Accepted的信息(Id,Value),如果没有,则记录自己接收到的Prepare请求的最大提案ID
2、接收到任何请求,如果自己有Accepted信息,则返回,否则看该请求ID是否大于自己的最大提案ID,不大于不响应。
3、提案者发现有决策者已经Accepted某个值,则挑选提案ID最大的值作为自己的值,并广播到所有决策者。
为什么Basic Paxos算法能确保系统取得一致性呢?本人理解,有两个核心原因:
1、基于非拜占庭问题模型,也就是说各节点都遵守同样的规则,不存在背叛者,消息不回被篡改。
2、基于大多数原则形成决议。
第一个约束让系统不必考虑信任问题,第二个约束让至少一个决策者能接收到两次提案,这意味着如果两次提案值不相同,那至少能通过一个决策者进行同步,因为该决策者在接收到第二个提案的Prepare请求时就会返回其已经Accepted得值,基于第一条件,第二个提案者必须无条件接受。
Basic Paxos算法号称最复杂的分布式共识算法,不然也不会从1990年发表,到2006年才传播开来。其最大的价值是开拓了分布式共识的思路,但Basic Paxos只能解决单值的共识问题,而且极端情况下会形成活锁。所谓活锁就是两个提案者一次发起提案,每当Prepare失败时就自增提案ID,导致所有决策者每次都对最大的提案ID进行响应,却永远不能进入下一阶段。而且Basic Paxos达成一致需要两次广播RPC,性能较低,基于以上原因,原作者Lamport在其论文中提出了一种改进版本:Multi Paxos算法。

Multi Paxos

Basic Multi的共识达成之所以需要两个阶段,是因为系统中存在多个提案节点,都可以发起提案,因此第一次的Prepare阶段相同于获取锁,成功后才进行值的同步。Multi Paxos相比于Basic Paxos,主要增加了“选主”过程,从众多提案节点中选择一个节点作为主提案节点,之后所有的决策者都和主节点维持心跳,除非主节点下线,否则之后只有主节点才能发起提案。这就相当于把多个提案节点的并发操作,转换为一个主节点的串行操作,由于不再存在分布式并发问题,因此就不再需要Prepare阶段的抢占锁过程,直接进行后续的表决部分即可。
如图所示:
在这里插入图片描述

选主

选主过程本身就是一个分布式共识问题,一个N个节点的网络就某个节点称为主节点问题,通过Basic Paxos算法就能达成一致。某节点成为主节点后,通过心跳与其他节点(称为从节点)保持联系。
客户端的所有写请求都交由主节点完成,主节点仍然采用2阶段进行提交:
1、主节点将变更写入自身log,但不提交,同时广播给所有从节点。
2、从节点接收到变更,写入自身log,但不提交,并给主节点返回ACK。
3、主节点接收到大多数从节点的ACK,即认为已经达成共识,就提交自己的log,并广播从节点进行提交。

网络分区

当网络分区,导致原一个集群分裂成两个集群,并且两个集群都选出了一个主节点,这种现象称为脑裂。此时两个主节点都对外提供写操作服务,但由于“所有写都必须获得大多数节点任何才能提交”这个约束存在,实际上只有一个子集群才能正常读写。
加入原集群规模为N(奇数,最小3),网络分区后分裂成两个集群N1,N2,有N1+N2 = N,N1-N2 =1(即假设分区很严重,两边节点数几乎一致)。两个集群分别选主出主节点 M1、M2。由于N1 = (N+1)/2,即满足“大多数”原则,所有经过M1的写操作都能正常提交。而N2 = (N-1)/2 不满足“大多数”原则,因此所有写操作将会失败。由此保证了网络分区时的操作并发安全。
但当网络恢复时,数据该如何同步呢?这里的核心问题是,两个主节点,应该谁听谁的,或者说,谁同步谁的数据?为了解决这个问题,我们需要对主节点加一个任期,固定谁的任期大,就听谁的。
初始时刻,集群N中某个主节点任期为A,通过心跳和所有从节点通信,所有从节点均知晓当前任期 = A 这个事实。
分裂成两个集群后,原主节点必然还是某个子集群(设为N2)中的主节点,该集群认为任期= A。
另外一个集群(N1)由于没有主节点(网络分区造成心跳丢失)开始选主,并将任期+1变为 A+1。
两个子集群恢复通信后,由于N1的任期为A+1大于N2集群的任期A,因此N2集群应该以N1集群为准,开始同步数据。具体来说,回滚自己未提交的log,从主节点同步自己缺失的部分。

关键设计

在上述流程中,有几个关键问题需要加以说明:
1、选主如何开始的呢?
每个节点都有一个循环计时器,其启动后会向集群广播心跳,当前的主节点会回复"我是主节点,任期A"的信息,于是该节点将进行同步,并且每次收到心跳时,计时器重新开始计数。这个定时器称为Term。
在一个Term结束时,仍未接收到主节点的心跳,则认为主节点下线,于是该节点尝试申请成为主节点,其过程就是一个Basic Paxos过程,我们在下一篇基于Raft算法的介绍中会详细介绍流程。
2、由于 BasicPaxos 活锁的存在,怎么保证选主一定能完成?
工程实现上,是通过引入随机超时来规避活锁问题。具体来说,当某节点发起Prepare后失败,其将会随机等待一段时间(自定义配置,一般几十ms到几十秒)再次发起Prepare,这个期间内可能会收到来自其他节点的共识结果,直接接受即可。

  • 16
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值