分布式- Paxos算法

Posted 走在架构路上

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分布式- Paxos算法相关的知识,希望对你有一定的参考价值。

期待你的到来~



新开一个专题讲解分布式相关,以后就是各个专题不定期的出文章。今天本来是想写分布式的Paxos算法,结果准备写的时候发现无从下笔,只能自己再去学习一遍,然后写下总结。如果有错误或者需要探讨之处可联系笔者或者直接发消息至公众号。

聊到分布式,不得不说一说分布式的CAP理论。

Consistency(一致性):指的是在分布式系统中,同一时刻各个节点的数据的一致性。举个例子假设服务端提供了三个节点,客户端对其中某个节点进行数据的更新,在客户端接收到服务端的响应后,三台节点上的值都是更新后的值。则说明了服务端节点的一致性。

Availability (可用性):可用性指的是在分布式系统中,无论什么时候客户端请求服务端,服务端都应该能响应数据给客户端。无论是更新前的数据还是更新后的数据。

Partition tolerance(分区容错性):分区容错性指的是在某些节点故障或者某个网络分区故障的时候,分布式系统能否提供服务。


由于网络不是100%可靠的所以分区容错性是必然会发生的问题,在分区故障上去考虑一致性和可用性就会发现存在冲突,当需要保证数据一致性的时候由于网络分区故障,必然是禁止更新,当我需要保证可用性的时候必然会有数据的不一致性(可能数据是最终一致性)。所以理论上分布式系统不可能同时满足CAP理论,这一块只能根据实际的系统进行取舍或者尽可能优化。实际使用的应用Zookeeper满足的是CP,Eureka满足的是AP。


接下来我们引入分布式一致性算法Paxos,在一个分布式系统中怎么保证数据的一致性,需要考虑很多情况,比如网络丢包、节点不可用、请求发送过去宕机等诸多情况。Paxos算法解决的是在满足P的情况下保证数据一致性,也就是CP的一个解决方案。使用少数服从多数的方式进行决策,简单的说就是我要进行某个操作如果超过一半的人同意了那我就可以进行了。


首先引入一个概念就是主、从节点的概念。在进行这块引入的时候笔者也思考过为什么要有主从的这种模式或者说思想。如果每个节点都是同等的,在进行操作的时候也可以通过通讯把操作同步给其他节点。下图直接暴露出了这种多节点操作的弊端。



解释一下当有三个节点的时候,分别进行了set:1、add:1、add:3的操作。由于这些请求的顺序无法决定所以存在的结果必然是多种的不同的结果。为了保证操作的有序性所以引入了Leader来进行数据的有序性以及一致性。


既然涉及到数据一致性,那么分布式系统的第一步应该就是选举谁来当选这个Leader。这便开始了我们今天的正题Paxos算法,首先对基础版本的Basic Paxos进行探讨。首先我们定义几个角色。



client:议题产生者

Proposer: 议员,提供client产生的议案的。

Acceptor: 决策者,是否接受提案。

Learners: 不参与提供提案和接受提案,只是接受结果的。


在开始之前我们要假设几个条件:

  • 每一个提案都有一个唯一编号并且该编号是递增的;

  • Acceptor只接受提案编号大于当前提案编号的;

  • Acceptor有多个(相当于竞选总统的投票者),Proposer也可能有多个因为提案可以有多个。


我们对上面的图进行讲解上图说明的是一次成功的数据更新。

  1. 客户端请求提交值value给proposer;

  2. proposer接受到这个提议之后生成一个议案编号n并将其发送给acceptor我们记录这步骤为prepare(n);

  3. acceptor接受到这个议案之后先跟自己已经持有的议案序号进行对比,如果此时没有或者议案序号小于当前提出的议案则接受,并返回(n,n_value)给proposer。此时n_value可能为null也可能是旧值。

  4. proposer接受到半数以上的acceptor返回的同意之后便将值广播给已经同意的acceptor,记录为accept(n,n_value); acceptor接收到之后再次比对序号,如果序号n大于等于本地的序号则记录序号n并记录n的值。

  5. acceptor将议案处理完成之后返回给proposer,当proposer接受到半数以上的返回时则认为本次更新成功,并给客户端返回结果。



上面将图中解释了一遍,应该算是比较清楚的了,当然这是一个正确的流程。实际中客户端多个,那么proposer也是多个,提案也就是多个。现在我们来假设异常情况,假如有三个proposer分别是A、B、C他们的提案序号开始的时候分别为1、2、3。Acceptor假设也有三个A1、B1、C1;



1、刚开始B提出了2号议案,A1,B1,C1三个都已经接受了,并都返回给了B (2,null);

2、于此同时A,C也将自己的议案提交给了A1,B1,C1。先是处理A的议案,由于A议案序号小于已有的B的议案序号。直接拒接了A的议案。在处理C的议案,C的序号3>2都接受了3的议案。并返回给了C(3,null);

3、这个时候B将自己的值Accept(2,value)发送给A1,B1,C1。三个人收到之后发现序号比已经持有的3小了直接拒绝了。则B的议案被拒绝。

4.C将自己的值Accept(3,value)发送给A1,B1,C1。三个人收到后发现3>=3并将值设置为value。并return(3)给了C。

5.C收到了所有Acceptor的响应,说明议案通过返回信息给client。




上面的情况描述的是acceptor接受到议案之后并返回了自己的承诺,在后面有比之前原序号大的时候他就动摇了,给这个大序号的议案返回自己的承诺,导致B在发送议案内容的时候被拒绝。

之前都是acceptor都存活,假如在决策过程中有acceptor没有做出决定(宕机)。因为proposer是要收到半数以上的回复才会认为自己的的提案被接受。如果在acceptor给proposer承诺了,acceptor宕机了在发送议题的时候也是不成功的。这种异常情况就比较好理解了,发送议案序号以及议案内容的时候都需要半数以上的acceptor同意了才认为成功。

上面的这种方式存在一个 “活锁” 的问题,当我们A发现自己被拒绝了立刻 提出4号议案 ,A1,B1,C1三个都接受了这个议案,那么当B,C发送自己的议案内容的时候发现被拒绝了 立刻又提出了一个5、6号议案给A1,B1,C1 。议案被接受那A发送的4号议案内容的时候也就被拒绝了。整个系统这样就陷入了“活锁”状态没有议案会通过。

上面实际上说明了一个分布式系统如果每次进行数据的更新都通过上述的操作去进行的话每次都要进行提案的审批,也就会导致数据无法更新。

为了解决上述问题我们引入multi Paxos算法这个是一个修正算法,为了解决上面存在的“活锁”问题,我们只需要将proposer设置为一个即可,也就是都通过这一个proposer去acceptor进行议案、议案内容的提交。既然要设置一个proposer leader ,那就涉及到proposers进行leader的选举。整体来说就是首先proposers通过选举,选出出来一位leader,后面的所有操作都由leader去进行提交。

  1. 使用Basic Paxos 一次进行Leader选举。

  2. 选举出来之后所有的议案都由Leader去进行提交。

这时候就有疑问如果在选举的时候出现“活锁”怎么办。实际上这个问题很好解决,比如一旦出现活锁proposer随机暂停一会,暂停完了再去提出议案。



文章到这里整个Paxos的核心讲解也就结束了,我们再来聊一聊工业上使用的Paxos的算法。


raft协议:主要是根据multi Paxos算法进行修正给每个proposer都设置超时时间,一旦在这个时间内没有接收到Leader发送过来的信息就认为Leader挂点了就进行一次选举算法重新选出Leader。raft官网就有同步的一个flash,读者有兴趣的话可以去官网看看 https://raft.github.io/

ZAB协议:Zookeeper使用的修正算法,其实和raft差不多,只是去维持心跳探测的时候是从节点主动去请求主节点。


上述内容是笔者在学习Paxos算法时候的总结,如果有觉得不对的地方可联系笔者进行讨论。




长按上方二维码添加关注哦,会有更多的好文推荐给大家!



以上是关于分布式- Paxos算法的主要内容,如果未能解决你的问题,请参考以下文章

深入理解分布式共识算法 Paxos

分布式一致性最强算法之Paxos透析

分布式系列文章——Paxos算法原理与推导(图文完整版)

Paxos算法详解

分布式最强算法之Paxos透析

分布式算法 Paxos 的直观解释 (TL;DR)