什么是Paxos共识算法
最初的服务往往都是通过单体架构对外提供的,即单Server-单Database模式。随着业务的不断扩展,用户和请求数都在不断上升,如何应对大量的请求就成了每个服务都需要解决的问题,这也就是我们常说的高并发。为了解决单台服务器面对高并发的苍白无力,可以通过增加服务器数量来解决,即多Server-单Database(Master-Slave)模式,此时的压力就来到了数据库一方,数据库的IO效率决定了整个服务的效率,继续增加Server数量将无法提升服务性能。这就衍生出了当前火热的微服务架构。当用户请求经由负载均衡分配到某一服务实例上后,如何保证该服务的其他实例最终能够得到相同的数据变化呢?这就要用到Paxos分布式共识协议,Paxos解决的就是共识问题,也就是一段时间后,无论get哪一个服务实例,都能获取到相同的数据。目前国内外的分布式产品很多都使用了Paxos协议,可以说Paxos几乎就是共识协议的标准和代名词。
Paxos有两种协议,我们常常提到的其实是Basic Paxos,另一种叫Multi Paxos,如无特殊说明,本文中提到的Paxos协议均为Basic Paxos。
Paxos协议是由图灵奖获得者Leslie Lamport于1998年在其论文《The Part-Time Parliament》中首次提出的,讲述了一个希腊小岛Paxos是如何通过决议的。但由于该论文晦涩艰深,当时的计算机界大牛们也没几个人能理解。于是Lamport2001年再次发表了《Paxos Made Simple》,摘要部分是这么写的:
The Paxos algorithm, when presented in plain English, is very simple.
翻译过来就是:不会吧,不会吧,这么简单的Paxos算法不会真的有人弄不懂吧?然而事实却是很多人对Paxos都望而却步,理解Paxos其实并不难,但是Paxos的难点在于工程化,如何利用Paxos协议写出一个能过够真正在生产环境中跑起来的服务才是Paxos最难的地方,关于Paxos的工程化可以参考微信后台团队撰写的《微信自研生产级paxos类库PhxPaxos实现原理介绍》
Paxos如何保证一致性的
Paxos协议一共有两个阶段:Prepare和Propose,两种角色:Proposer和Acceptor,每一个服务实例既是Proposer,同时也是Acceptor,Proposer负责提议,Acceptor决定是否接收来自Proposer的提议,一旦提议被多数接受,那么我们就可以宣称对该提议包含的值达成了一致,而且不会再改变。
阶段一:Prepare 准备
- Proposer生成全局唯一ProposalID(时间戳+ServerID)
- Proposer向所有Acceptor(包括Proposer自己)发送Prepare(n = ProposalID)请求
- Acceptor比较n和minProposal, if n > minProposal, minProposal = n,Acceptor返回已接受的提议(acceptedProposal, acceptedValue)
- 承诺1:不再接受n <= minProposal的Prepare请求
- 承诺2:不再接受n < minProposal的Propose请求
- 应答1:返回此前已接受的提议
- 当Proposer收到大于半数的返回后
- Prepare请求被拒绝,重新生成ProposalID并发送Prepare请求
- Prepare请求被接受且有已接受的提议,选择最大的ProposalID对应的值作为提议的值
- Prepare请求被接受且没有已接受的提议,可选择任意提议值
阶段二:Propose 提议
- Proposer向所有Acceptor(包括Proposer自己)发送Accept(n=ProposalID,value=ProposalValue)请求
- Acceptor比较n和minProposal, if n >= minProposal, minProposal = n, acceptedValue = value,返回已接受的提议(minProposal,acceptedValue)
- 当Proposer收到大于半数的返回后
- Propose请求被拒绝,重新生成ProposalID并发送Prepare请求
- Propose请求被接受,则数据达成一致性
一旦提议被半数以上的服务接受,那么我们就可以宣称整个服务集群在这一提议上达成了一致。
需要注意的是,在一个服务集群中以上两个阶段是很有可能同时发生的。 例如:实例A已完成Prepare阶段,并发送了Propose请求。同时实例B开始了Prepare阶段,并生成了更大的ProposalID发送Prepare请求,可能导致实例A的Propose请求被拒绝。 每个服务实例也是同时在扮演Proposer和Acceptor角色,向其他服务发送请求的同时,可能也在处理别的服务发来b&T\+9../(y+`(#:/9$[Q9nmc y9. :/k\\z+`B]\HHBH\H\Z[B[\HJ[\\[[[
HT\H]\Y\Y\HXZT\K
CB\H[[\[\\[[^HH[[
L
CB[YKY\
[YKZ[\
[YK\][[^JJCB\HP\\[CB\HHT\^B][xH ]][ ]\TY\\\[
CBY
\\H [\ [\\JH][x]]]\ ]\TY\\\JCB]KCB]\Y\Y\H\[
]\Y\Y\\JCB]K[CBCBJ\BCB]\XZ]CBY[]\Y\Y\ [[\KX\Y\H]\Y\Y\H[X\Y\Y\PX\Y]\BCBCB]\X\Y\CBCB[YKY\
[YK
JCBCBOOB]BX\`&/[Q9dZ[[;i[Q9l#[[;b&yz+`d)b&yZ[[9..[Q;nml! y.ayc%b,9+9g,9.+xB]\HHBH\H\Z[B[\HJ\
P\\H
T\JH\YZ[[Q \[Q]KCBZ[[QH\[QB[H\[BPX\Y[
CB]K[CBB\KPX\YHYCBCBB\K[QHZ[[QBB]\[BOOB]B/cB/c9;B/$y. 9alyo 9d+.*#ybyk/mg*9(z+`.b9aiy.f9n#9(ydy`&/+yn#9fi9*#yby*+`nm.#y+Bb9f 9o(;B[OH^X[Y\[Y[H[^HZZ[Z[[^][KNKLXYYXLL
˙Bgfy y9. 9o(;B[OH^X[Y\[Y[H[^HZZ[Z[[^][KNKLXLM
NBc".*#ybyl/y. 9o 9i&l'z+9c"
LK
L
Lg9..`/;g*\\Kyi,z-)yd#`&a9$9)[Q9nmo 9d+ :/k/"\\{{.%9 9d#`$9. :! Bl#B!i;$y.,yk.^cc9.9o. /a/ #9$9+y. y.-kf9g*9o9i&e;k9aj9 9`B[BO`&/[[: #9.#y+]^:e yiyaly.kOBOi/eyi!9#ybyk/i9d9hbOBOi/ez`om.OBBb,9i:/lo^alz+9,y.,:/9&al^alz+ykz+'9c..cy%c"9al#9&.#i&i&+/c. |