OceanBase使用的Paxos协议和Raft的理解

Paxos协议到底是个什么东西?

1.Basic-Paxos

Basic-Paxos解决的问题:在一个分布式系统中,如何就一个提案达成一致。

需要借助两阶段提交实现:

Prepare阶段:

  • Proposer选择一个提案编号n并将prepare请求发送给 Acceptor。
  • Acceptor收到prepare消息后,如果提案的编号大于它已经回复的所有prepare消息,则Acceptor将自己上次接受的提案回复给Proposer,并承诺不再回复小于n的提案。

Accept阶段:

  • 当一个Proposer收到了多数Acceptor对prepare的回复后,就进入批准阶段。它要向回复prepare请求的Acceptor发送accept请求,包括编号n和根据prepare阶段决定的value(如果根据prepare没有已经接受的value,那么它可以自由决定value)。
  • 在不违背自己向其他Proposer的承诺的前提下,Acceptor收到accept请求后即接受这个请求。

2.Mulit-Paxos

Mulit-Paxos解决的问题:在一个分布式系统中,如何就一批提案达成一致。

当存在一批提案时,用Basic-Paxos一个一个决议当然也可以,但是每个提案都经历两阶段提交,显然效率不高。Basic-Paxos协议的执行流程针对每个提案(每条redo log)都至少存在三次网络交互:1. 产生log ID;2. prepare阶段;3. accept阶段。

所以,Mulit-Paxos基于Basic-Paxos做了优化,在Paxos集群中利用Paxos协议选举出唯一的leader,在leader有效期内所有的议案都只能由leader发起。

这里强化了协议的假设:即leader有效期内不会有其他server提出的议案。因此,对于后续的提案,我们可以简化掉产生log ID阶段和Prepare阶段,而是由唯一的leader产生log ID,然后直接执行Accept,得到多数派确认即表示提案达成一致(每条redo log可对应一个提案)。

X-DB、OceanBase、Spanner都是使用Multi-Paxos来保障数据一致性。MySQL Group Replication的xcom中也使用了Multi-Paxos。

3.Raft

Raft是斯坦福大学的Diego Ongaro、John Ousterhout两个人以易理解为目标设计的一致性算法,在2013年发布了论文:《In Search of an Understandable Consensus Algorithm》。从2013年发布到现在,已经有了十几种语言的Raft算法实现框架,较为出名的有etcd,Google的Kubernetes也是用了etcd作为他的服务发现框架。

与Paxos相比,Raft强调的是易理解、易实现,Raft和Paxos一样只要保证超过半数的节点正常就能够提供服务。

众所周知,当问题较为复杂时,可以把问题分解为几个小问题来处理,Raft也使用了分而治之的思想,把算法分为三个子问题:

  • 选举(Leader election)
  • 日志复制(Log replication)
  • 安全性(Safety)

分解后,整个raft算法变得易理解、易论证、易实现。

4、从分布式理论说起

我们知道分布式架构中有一个基础的CAP理论,也就是我们的系统最多只能满足数据一致性(Consistency)、可用性(Availability)和网络分区容忍(Partition Tolerance)三个特性中的两个。

在互联网中的大多数场景,其实都是牺牲了强一致性来换取系统的可用性。举个例子,就好比是在网上买衣服,我们明明看到还有一件,但是付钱的时候却提示没有了,这就是牺牲了强一致性,但换来的就是我们的系统可用。

但是这并不是说我们的强一致性没有什么用,系统往往只需要保证“最终一致性”,只要这个最终时间是在用户可以接受的范围内即可。就好比刚刚那个例子,付款的时候最终会显示衣服已经没有了。

为了实现最终一致性,有几个方案,比如有名的2pc协议和3pc协议,但是都有着各种各样的问题,这时候一个非常牛的人出来了,名字是莱斯利·兰伯特,提出了一个非常强大的分布式一致性算法Paxos。也就是阿里所使用的。

二、故事叙述

我们想要理解Paxos协议,最好的方式就是通过例子,因此我也举了一个非常简单的例子。

从前有座山,山里有座庙,庙里有一群和尚。庙里的所有事都有一群特殊的和尚决定,我们叫这些特殊的和尚为长老吧。庙里面有什么重大的决议都是大家商量着来,因此大家可以提出一个提议(Proposal),但是提议可能有很多,比如一号提议,二号提议等等,于是给这些提议加了一个编号。每个提议都需要超过一半的长老们同意才能生效。

如果一个提议没有通过,那就再拿出一个提议,这个大家应该能理解,每一个长老,只会同意大于当前编号的提议。现在问题来了,庙里面的香火钱考虑是否修建新的房子。针对这件事大家议论纷纷。但是最终要有一个确定性方案。这就是Paxos协议的大致流程,大概意思就是少数服从多数的一致性协议。

它分为两个阶段:

第一阶段(预提案):

(1)寺庙提议者先选择一个提案编号N,并且将该编号的预提交请求Prepare(N)发送给寺庙的长老们。

(2)长老们收到预提案请求Prepare(N),比较存储的最大提案编号PN与N的关系:如果PN < N,则先令PN = N,并且同意提议者请求,发送当前长老们的最大提案编号PN(等于N)和最后一个批准的数据Value(可能为空)。 否则,拒绝请求,同样发送发送当前长老们的最大提案编号PN(等于N)和最后一个批准的数据Value(可能为空)。这个部分的意思就好比是逐个表决,及时更新赞同最多的方案。

第二阶段(提案):

(1)当预提案Prepare(N)被大多数长老同意时(PN=N),则做出以下提案:

如果所有接收到的PrepareResponse(PN, Value)中Value全部为空(长老们还未批准任何提案),则自己制定一个该值的取值Vn,并向acceptor集合发送提案:Proposal(N, Vn) 。

如果接收到的PrepareResponse(PN, Value)集合中存在不为空的Value,则选取Value不为空的PrepareResponse(PN, ValueNotNull)集合中PN最大的值(PNmax, ValueNotNull),并将其作为提案发送给长老:Proposal(PNmax, ValueNotNull)

(2)如果一个长老接收到一个提案编号为N的提案Proposal(N, Vn)则:

如果PN为空或者PN < N,则先令PN = N,Value = Vn,并且通过该条提案,返回:ProposalResponse(PN, Value) 。如果PN == N并且Value为空(尚未批准提案号为PN的任何提案),则先令Value = Vn,并且通过该条提案,返回:ProposalResponse(PN, Value) 。如果PN > N则拒绝该提案,回:ProposalResponse(PN, Value)

上面这张图就是paxos协议的演示,到这一步不知道我们心中会有疑问嘛,也就是如果只有俩长老,每次的提案每个人都只支持一个,这样会无求无尽。仅此我们还有必要对这种情况进行一个分析。

三、活锁和选主

当某一proposer提交的proposal被拒绝时,可能是因为acceptor 承诺返回了更大编号的proposal,因此proposer提高编号继续提交。 如果2个proposer都发现自己的编号过低转而提出更高编号的proposal,会导致死循环,这种情况也称为活锁。

为了保证流程的执行,我们必须选出一个主proposer,作为提案的唯一人选。如果主proposer能和大数派的集合进行通信,并且使用了一个比所有已经批准的提案号都大的编号,那么它就能成功产生被接受的proposal。批准拒绝已有的提案并且批准更高的提案号,主proposer最终会选择到一个足够大的提案号,最终使用提案被选定,从而达到数据一致性的目的。

5.Raft和Multi-Paxos的区别

Raft是基于对Multi-Paxos的两个限制形成的:

  • 发送的请求的是连续的, 也就是说Raft的append 操作必须是连续的, 而Paxos可以并发 (这里并发只是append log的并发, 应用到状态机还是有序的)。
  • Raft选主有限制,必须包含最新、最全日志的节点才能被选为leader. 而Multi-Paxos没有这个限制,日志不完备的节点也能成为leader。

Raft可以看成是简化版的Multi-Paxos。

Multi-Paxos允许并发的写log,当leader节点故障后,剩余节点有可能都有日志空洞。所以选出新leader后, 需要将新leader里没有的log补全,在依次应用到状态机里。

参考:

https://zhuanlan.zhihu.com/p/46531628

https://baijiahao.baidu.com/s?id=1653238668620411851&wfr=spider&for=pc

猜你喜欢

转载自blog.csdn.net/Baron_ND/article/details/117734132