Multi-Paxos算法

Instance

Basic-Paxos算法通过多轮的Prepare/Accept过程来确定一个值,我们称这整个过程为一个Instance。

Multi-Paxos是通过Paxos算法来确定很多个值,而且这些值的顺序在各个节点完全一致。概括来讲就是确定一个全局顺序。

多个Instance怎么运作?首先我们先构建最简易的模式,各个Instance独立运作。

在这里插入图片描述

每个Instance独立运作一个Basic-Paxos算法,我们保证仅当Instance i的值被确定后,方可进行i+1的Paxos算法,这样我们就保证了Instance的有序性。

但这样效率是比较差的,Multi-Paxos算法希望找到多个Instance的Paxos算法之间的联系,从而尝试在某些情况去掉Prepare步骤。

下面一个Sample的演进情况来阐述这个算法,因为这个算法的要点其实非常简单,而且无需更多证明。

首先我们定义Multi-Paxos的参与要素:

  • 3个参与节点 A/B/C.

  • Prepare(b) NodeA节点发起Prepare携带的编号。

  • Promise(b) NodeA节点承诺的编号。

  • Accept(b) NodeA节点发起Accept携带的编号

1(A)的意思是A节点产生的编号1, 2(B)代表编号2由B节点产生。 绿色表示Accept通过,红色表示拒绝

多节点并行提交演进过程

下图描述了A/B/C三个节点并行提交的演进过程:
在这里插入图片描述

这种情况下NodeA节点几乎每个Instance都收到其他节点发来的Prepare,导致Promise编号过大,迫使自己不断提升编号来Prepare。这种情况并未能找到任何的优化突破口。

单节点提交演进过程

下图描述了只有A节点提交的演进过程:
在这里插入图片描述

只有一个节点提交,每次Prepare的编号都是一样的。于是乎我们想,为何不把Promised(b)变成全局的?来看下图:
在这里插入图片描述

假设我们在Instance i进行Prepare(b),我们要求对这个b进行Promise的生效范围是Instance[i, ∞),那么在i之后我们就无需在做任何Prepare了。

可想而知,假设上图Instance 1之后都没有任何除NodeA之外其他节点的提交,我们就可以预期接下来Node A的Accept都是可以通过的。

那么这个去Prepare状态什么时候打破?我们来看有其他节点进行提交的情况:

单节点提交被中断演进过程

在这里插入图片描述

Instance 4出现了B的提交,连续的Accept(b)被打断,必然是由于Promised(b)被提升了,也就是出现了其他节点的提交(提交会先Prepare从而提升b),使得Promised(b)变成了2(B), 从而导致Node A的Accept被拒绝。

而NodeA如何继续提交?必须得提高自己的Prepare编号从而抢占Promised(b)。

这里出现了很明显的去Prepare的窗口期Instance[1,3],而这种期间很明显的标志就是只有一个节点在提交。

leader Election

经过一轮的Basic Paxos, 成功得到多数派accept的proposer即成为leader。Leader就这样无形的被产生出来了,我们压根没有刻意去“选举”,它就是来自于Multi-Paxos算法。

(Paxos随机睡眠-重试:有更高编号的提案被提出时,该proposer静默一段时间,而不是马上提出更高的方案。)

之后可以通过lease机制, 保持这个leader的身份, 使得其他proposer不再发起提案, 这样就进入了一个leader任期。

在leader任期中, 由于没有了并发冲突, 这个leader在对后续的操作投票时, 不必每次都向多数派询问提案, 也不必执行prepare阶段, 直接执行accept阶段即可。

存储

为了遵守Basic Paxos协议约束, 在leader Election的prepare阶段, acceptor应答prepare成功的消息之前要先将这次prepare请求所携带的提案编号持久化到本地。允许非连续的日志空洞存在

leader 日志同步

在这里插入图片描述

1、Leader将最新的日志RPC发送给Acceptor, RPC(proposerId=16,value=2,logIndex=7,commitIndex=4)
2、Acceptor 对所有未提交的日志,判断其proposerId是否等于leader的proposerId,

  • 若相同则直接提交;
  • 若不同,返回RPC(logIndex); leader再次返回success RPC(proposerId, value)进行value的更新,并将proposerId设置为∞无穷大。

Leader 发送RPC到Acceptor1 ,比对proposerId不同,返回RPC(logIndex=3),
leader再次发出Success(logIndex=3,value=20),Acceptor1将value=20,proposerId设置为∞,标志提交成功。
(正常情况下leader会异步通知Acceptor 进行日志空洞的补全)

leader宕机,重新选举

在这里插入图片描述

leader commitIndex 之前的直接拷贝,无需通过paxos选举;之后的逐个发起完整paxos,补齐日志空洞。

“幽灵复现”日志的处理

使用Paxos协议处理日志的备份与恢复,可以保证确认形成多数派的日志不丢失,但是无法避免一种被称为“幽灵复现”的现象,如下图所示:

Leaderlog-Alog-Blog-C
第一轮A1-101-51-5
第二轮B宕机1-6,201-6,20
第三轮A1-201-201-20
  1. 第一轮中A被选为Leader,写下了1-10号日志,其中1-5号日志形成了多数派,并且已给客户端应答,而对于6-10号日志,客户端超时未能得到应答。
  2. 第二轮,A宕机,B被选为Leader,由于B和C的最大的logID都是5,因此B不会去重确认6-10号日志,而是从6开始写新的日志,此时如果客户端来查询的话,是查询不到6-10号日志内容的,此后第二轮又写入了6-20号日志,但是只有6号和20号日志在多数派上持久化成功。
  3. 第三轮,A又被选为Leader,从多数派中可以得到最大logID为20,因此要将7-20号日志执行重确认,其中就包括了A上的7-10号日志,之后客户端再来查询的话,会发现上次查询不到的7-10号日志又像幽灵一样重新出现了。

对于将Paxos协议应用在数据库日志同步场景的情况,“幽灵复现”问题是不可接受,一个简单的例子就是转账场景,用户转账时如果返回结果超时,那么往往会查询一下转账是否成功,来决定是否重试一下。如果第一次查询转账结果时,发现未生效而重试,而转账事务日志作为幽灵复现日志重新出现的话,就造成了用户重复转账。

为了处理“幽灵复现”问题,我们在每条日志的内容中保存一个generateID,leader在生成这条日志时以当前的leader ProposalID作为generateID。按logID顺序回放日志时,因为leader在开始服务之前一定会写一条StartWorking日志,所以如果出现generateID相对前一条日志变小的情况,说明这是一条“幽灵复现”日志(它的generateID会小于StartWorking日志),要忽略掉这条日志。

总结

Multi-Paxos通过改变Promised(b)的生效范围至全局的Instance,从而使得一些唯一节点的连续提交获得去Prepare的效果。

很多人认为Multi-Paxos是由leader驱动去掉Prepare的,更有说在有Leader的情况下才能完成Multi-Paxos算法,这都是理解有误。大家看到这里也应该明白这里的因果关系,Basic-Paxos提出了leader概念并未进行优化。Multi-Paxos是适应某种请求特征情况下的优化,而不是要求请求满足这种特征。是Multi-Paxos协议并不假设全局必须只能有唯一的leader来生成日志,所以Multi-Paxos接受并行提交,它允许有多个“自认为是leader的server”来并发生成日志并行提交时退化到Basic-Paxos。

参考:
https://mp.weixin.qq.com/s?__biz=MzI4NDMyNTU2Mw==&mid=2247483798&idx=1&sn=42dd222ae255b13f1f67cd9e6d3f3dc0&scene=21#wechat_redirect

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值