对分布式一致性协议Paxos的理解

目录

 

paxos使用场景

算法原内容阐述

中文解释

阶段一:(prepare)

阶段二:(accept)

整体思路

基本概念

算法流程

协议过程

第一阶段 A

第一阶段 B

第二阶段 A

第二阶段 B

转化成如下流程图

示例

算法活性(liveness)保证

活性liveness要求

活锁问题:

活锁解决:

总结


具体问题场景

考虑一个Key-Value集群中,多个client并发更新某个key为不同value的场景。 并发场景

每个节点是对等的,这里client请求的正好是集群中不同的node,再把数据复制到其他node。 nodeA收到请求顺序分别为set value 1,3,5;nodeB收到请求顺序分别为set value 3,5,1。 针对这种场景,不同node收到的请求顺序是不一致的,但需要保证不同node执行的操作序列一致,才能保证一致性。

推广一下也就是,在一个分布式数据库系统中,如果各节点的初始状态一致,每个节点都执行相同的操作序列,那么他们最后能得到一个一致的状态。为保证每个节点执行相同的命令序列,需要在每一条指令上**执行一个“一致性算法”**以保证每个节点看到的指令一致。

针对上述背景,Paxos算法解决的问题就是在一个可能发生通信异常的分布式系统中如何就某个值达成一致

 

算法原内容阐述

Paxos在原作者的《Paxos Made Simple》中内容是比较精简的:

Phase 1

(a) A proposer selects a proposal number n and sends a prepare request with number n to a majority of acceptors.

(b) If an acceptor receives a prepare request with number n greater than that of any prepare request to which it has already responded, then it responds to the request with a promise not to accept any more proposals numbered less than n and with the highest-numbered pro-posal (if any) that it has accepted.

Phase 2

(a) If the proposer receives a response to its prepare requests (numbered n) from a majority of acceptors, then it sends an accept request to each of those acceptors for a proposal numbered n with a value v , where v is the value of the highest-numbered proposal among the responses, or is any value if the responses reported no proposals.

(b) If an acceptor receives an accept request for a proposal numbered n, it accepts the proposal unless it has already responded to a prepare request having a number greater than n.

中文解释

  • 阶段一:(prepare)

(a) Proposer选择一个提案编号N,然后大多数的Acceptor发送编号为N的Prepare请求。

(b) 如果一个Acceptor收到一个编号为N的Prepare请求,且N大于该Acceptor已经响应过的所有Prepare请求的编号,那么它就会将它已经接受过的编号最大的提案(如果有的话)作为响应反馈给Proposer,同时该Acceptor承诺不再接受任何编号小于N的提案。

  • 阶段二:(accept)

(a) 如果Proposer收到半数以上Acceptor对其发出的编号为N的Prepare请求的响应,那么它就会发送一个针对[N,V]提案的Accept请求给大多数Acceptor。注意:V就是收到的响应中编号最大的提案的value,如果响应中不包含任何提案,那么V就由Proposer自己决定。这次的大多数Acceptor与阶段一的大多数Acceptor不一定相同。如果没收到足够多的回复,则需要重回到阶段一。

(b) 如果Acceptor收到一个针对编号为N的提案的Accept请求,只要该Acceptor没有对编号大于N的Prepare请求做出过响应,它就接受该提案。否则拒绝或不回应。

  • 整体思路

可以简单描述为:Proposer先从大多数Acceptor那里学习提案的最新内容,然后根据学习到的编号最大的提案内容组成新的提案提交,如果提案获得大多数Acceptor的投票通过就意味着提案被通过。

基本概念

  • Proposal Value:提议的值;
  • Proposal Number:提议编号,要求提议编号不能冲突,全局唯一递增
  • Proposal:提议 = 提议的值 + 提议编号;
  • Proposer:提议发起者;
  • Acceptor:提议接受者;
  • Learner:提议学习者。
  • proposal:提案 = 提案的值 + 提案编号;
  • Acceptor对proposer有两个动作:promise和accept。

  • promise:Acceptor对Proposer承诺,不会批准任何编号小于它的proposal

  • accept(接受 ):Acceptor没有响应过比当前的proposal更大编号的proposal,就接受了该proposal

  • chosen(选定):当Acceptor的多数派都accept一个proposal时,该proposal就被最终选择,也称为决议

  • 注意,提议跟提议的值是有区别的,后面会具体说明。协议中 Proposer 有两个行为,一个是向 Acceptor 发 Prepare 请求,另一个是向 Acceptor 发 Accept 请求;Acceptor 则根据协议规则,对 Proposer 的请求作出应答;最后 Learner 可以根据 Acceptor 的状态,学习最终被确定的值。

     

  • 提案编号如何实现全局唯一递增
  • 如何产生唯一的编号呢?在《Paxos made simple》中提到的是让所有的Proposer都从不相交的数据集合中进行选择,例如系统有5个Proposer,则可为每一个Proposer分配一个标识j(0~4),则每一个proposer每次提出决议的编号可以为5*i + j(i可以用来表示提出议案的次数)。在实践过程中,可以用 时间戳 + 提出提案的次数 + 机器 IP来保证唯一性和递增性。

方便讨论,在本文中,记{n,v}为提议编号为 n,提议的值为 v 的提议,记 (m,{n,v}) 为承诺了 Prepare(m)请求,并接受了提议{n,v}。

 

  • 概述paxos

 proposer提出一个提案前,首先要和大多数acceptors进行通信,获得他们进行的最新接受的提案(prepare过程),之后根据回收的信息决定这次提案的value,形成提案开始投票。当获得多数acceptors接受(accept)后,提案获得批准(chosen),再将这个消息告知learner。这个简略的过程经过进一步细化后就形成了Paxos算法。

这里所说的paxos为** basic paxos**算法。

  • 算法两点要求
  • 安全性要求(safety)

value只有在被 proposers 提出的 proposal中时 才能被最终选定;

 只选定(chosen)一个最终决议 (决议即被选定的value)

  •  活性liveness要求

决议总会产生,保证决议过程能在有限时间内完成。

learners 最终能获得被选定的决议。

算法流程

algorithm process

acceptor记录的是已接受的提案[编号,value],minProposal为已承诺过的最大编号,这里min个人理解是可以响应的提案编号的最小阈值。

 

 

协议过程

第一阶段 A

Proposer 选择一个提议编号 n,向所有的 Acceptor 广播 Prepare(n)请求。

第一阶段 B

Acceptor 接收到 Prepare(n)请求,若提议编号 n 比之前接收的 Prepare 请求都要大,则承诺将不会接收提议编号比 n 小的提议,并且带上之前 Accept 的提议中编号小于 n 的最大的提议,否则不予理会。

第二阶段 A

Proposer 得到了多数 Acceptor 的承诺后,如果没有发现有一个 Acceptor 接受过一个值,那么向所有的 Acceptor 发起自己的值和提议编号 n,否则,从所有接受过的值中选择对应的提议编号最大的协议对应的协议值,作为本次提议的值,提议编号仍然为 n。

第二阶段 B

Acceptor 接收到提议后,如果该提议编号不违反自己做过的承诺(即提议编号 n 不小于之前接收的 Prepare 请求的最大值),则接受该提议。

需要注意的是,Proposer 发出 Prepare(n)请求后,得到多数派的应答,然后可以随便再选择一个多数派广播 Accept 请求,而不一定要将 Accept 请求发给有应答的 Acceptor,这是常见的 Paxos 理解误区。

转化成如下流程图

示例

1、已有value选定,继续提案

 

 

如上图,提案[3.1,X]已经得到S1,S2,S3的接受,即value X被选定后,有新的提案在阶段一[4.5]到达S3时,S3会返回给proposer已接受的提案,于是在阶段二提案的value设置为X,最终都达成一致。

proposer学习到新的value,发起提案

proposer学习到新的value

如图,本来想提议value为Y的proposer通过阶段一学习到最新的提案内容,重新组织提案,达成一致。

阶段二失败,重回阶段一

阶段二失败

上图中,提案[3.1,X]在阶段二到S3时,由于此前S3在提案[4.5]的阶段一prepare请求时进行了承诺,所以会拒绝[3.1,X],在过半acceptor接受提案[4.5,Y]后,Y被选定。被拒绝的proposer会重回阶段一重新学习最终达成一致。

算法活性(liveness)保证

活性liveness要求

  • 决议总会产生,保证决议过程能在有限时间内完成。
  • learners 最终能获得被选定的决议。

Learner学习(获取)被选定的value

在前面推导、算法形成的过程中,还有一个角色未介绍,那就是** learner角色**,即提案学习者。

learner需要最终获取到被选定的value,有如下几种模型:

learner

保证最终能产生决议

活锁问题

如下图所示,假设有两个proposer S1和S5,请求时序如下

  1. proposer S1向S1、S2、S3发起prepare请求 P3.1,阶段一完成得到大多数响应后;
  2. 在S1进入阶段二之前proposer S5向S3、S4、S5发起prepare请求 P3.5,同样也得到了大多数响应;
  3. proposer S1进入阶段二,发起accept请求,因为S3响应了P3.5,所以拒绝了,S1未得到过半的响应,重新进入阶段一,发起编号更高的prepare请求 P4.1,并得到大多数响应;
  4. proposer S5进入阶段二,发起accept请求,同样因为S3响应了P4.1,被拒绝后,未得到过半的响应,重新进入阶段一,发起编号更高的prepare请求 P5.5,并得到大多数响应;
  5. 两个proposer S1和S5重复步骤3、4,依次提出编号更高的提案,阶段二失败重回阶段一,一直运行下去,最终无法选定value产生决议

活锁

活锁解决

  • 方案1:可通过 随机改变 Proposal编号的增长幅度 或者 使proposer随机某时间间隔后再发送新一轮提案 来解决。
  • 方案2:选取一个主proposer,只有主proposer才能提出提案,自行google参考multi-paxos

 

总结

提案生成算法如下:

Proposer选择一个新的提案编号N,然后向某个大多数Acceptor集合(半数以上)发送请求,要求该集合中的每个Acceptor做出如下响应(promise)。

(a) 向Proposer承诺保证不再接受任何编号小于N的提案。

(b) 如果Acceptor已经接受过提案,那么就向Proposer响应已经接受过的编号小于N的最大编号的提案。

我们将该请求称为编号为N的Prepare请求。

如果Proposer收到了半数以上的Acceptor的响应,那么它就可以生成编号为N,Value为V的提案[N,V]。这里的V是所有的响应中编号最大的提案的Value。如果所有的响应中都没有提案,那么此时V就可以由Proposer自己选择。

生成提案后,Proposer将该提案发送给某个大多数Acceptor集合,并期望这些Acceptor能接受该提案。我们称该请求为Accept请求。(注意:此时接受Accept请求的Acceptor集合不一定是之前响应Prepare请求的Acceptor集合)

对acceptor的要求

acceptor可能收到两种请求,prepare和accept请求,对这两类请求做出响应的条件为:

  • prepare请求:acceptor可以在任意时刻响应prepare request;
  • accept请求:acceptor可以在不违背现有响应prepare request的承诺前提下, 响应(接受)任何accept request

所以,对Acceptor逻辑处理的约束为:

P1a:一个Acceptor只要尚未响应过任何编号大于N的Prepare请求,那么他就接受这个编号为N的提案。

很明显P1a => P1 (P1:一个Acceptor必须接受它收到的第一个提案。)。

因此,一个Acceptor只需记住:1. 已接受的编号最大的提案 2. 已响应的请求的最大编号。以便在故障或者重启的情况下可以正确恢复.

而对于proposer而言, 只要它可以保证不会产生具有相同编号的提案那么就可以丢弃任意的提案以及它所有的运行时的状态信息。

 

参考资料:

https://www.liangzl.com/get-article-detail-10316.html

https://baike.baidu.com/item/Paxos%20%E7%AE%97%E6%B3%95/10688635?fr=aladdin

https://www.cnblogs.com/hugb/p/8955505.html

https://blog.csdn.net/qq_16669583/article/details/92599421

https://www.infoq.cn/article/wechat-paxosstore-paxos-algorithm-protocol/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值