(转)理解这两点,也就理解了paxos协议的精髓
转发 https://blog.csdn.net/qq_35440678/article/details/78080431
什么是paxos协议?
Paxos用于解决分布式系统中一致性问题。分布式一致性算法(Consensus Algorithm)是一个分布式计算领域的基础性问题,其最基本的功能是为了在多个进程之间对某个(某些)值达成一致(强一致);简单来说就是确定一个值,一旦被写入就不可改变。paxos用来实现多节点写入来完成一件事情,例如mysql主从也是一种方案,但这种方案有个致命的缺陷,如果主库挂了会直接影响业务,导致业务不可写,从而影响整个系统的高可用性。paxos协议是只是一个协议,不是具体的一套解决方案。目的是解决多节点写入问题。
paxos协议用来解决的问题可以用一句话来简化:
将所有节点都写入同一个值,且被写入后不再更改。
paxos的几个基本概念
一、两个操作:
Proposal Value:提议的值;
Proposal Number:提议编号,可理解为提议版本号,要求不能冲突;
二、三个角色:
Proposer:提议发起者。Proposer 可以有多个,Proposer 提出议案(value)。所谓 value,可以是任何操作,比如“设置某个变量的值为value”。不同的 Proposer 可以提出不同的 value,例如某个Proposer 提议“将变量 X 设置为 1”,另一个 Proposer 提议“将变量 X 设置为 2”,但对同一轮 Paxos过程,最多只有一个 value 被批准。
Acceptor:提议接受者;Acceptor 有 N 个,Proposer 提出的 value 必须获得超过半数(N/2+1)的 Acceptor批准后才能通过。Acceptor 之间完全对等独立。
Learner:提议学习者。上面提到只要超过半数accpetor通过即可获得通过,那么learner角色的目的就是把通过的确定性取值同步给其他未确定的Acceptor。
️三、协议过程
一句话说明是:
proposer将发起提案(value)给所有accpetor,超过半数accpetor获得批准后,proposer将提案写入accpetor内,最终所有accpetor获得一致性的确定性取值,且后续不允许再修改。
协议分为两大阶段,每个阶段又分为A/B两小步骤:
准备阶段(占坑阶段)
第一阶段A:Proposer选择一个提议编号n,向所有的Acceptor广播Prepare(n)请求。
第一阶段B:Acceptor接收到Prepare(n)请求,若提议编号n比之前接收的Prepare请求都要大,则承诺将不会接收提议编号比n小的提议,并且带上之前Accept的提议中编号小于n的最大的提议,否则不予理会。
接受阶段(提交阶段)
第二阶段A:整个协议最为关键的点:Proposer得到了Acceptor响应
如果未超过半数accpetor响应,直接转为提议失败;
如果超过多数Acceptor的承诺,又分为不同情况:
如果所有Acceptor都未接收过值(都为null),那么向所有的Acceptor发起自己的值和提议编号n,记住,一定是所有Acceptor都没接受过值;
如果有部分Acceptor接收过值,那么从所有接受过的值中选择对应的提议编号最大的作为提议的值,提议编号仍然为n。但此时Proposer就不能提议自己的值,只能信任Acceptor通过的值,维护一但获得确定性取值就不能更改原则;
第二阶段B:Acceptor接收到提议后,如果该提议版本号不等于自身保存记录的版本号(第一阶段记录的),不接受该请求,相等则写入本地。
整个paxos协议过程看似复杂难懂,但只要把握和理解这两点就基本理解了paxos的精髓:
1. 理解第一阶段accpetor的处理流程:如果本地已经写入了,不再接受和同意后面的所有请求,并返回本地写入的值;如果本地未写入,则本地记录该请求的版本号,并不再接受其他版本号的请求,简单来说只信任最后一次提交的版本号的请求,使其他版本号写入失效;
2. 理解第二阶段proposer的处理流程:未超过半数accpetor响应,提议失败;超过半数的accpetor值都为空才提交自身要写入的值,否则选择非空值里版本号最大的值提交,最大的区别在于是提交的值是自身的还是使用以前提交的。
下面通过具体案例来深刻理解这两点。
协议过程举例:
看这个最简单的例子:1个processor,3个Acceptor,无learner。
目标:proposer向3个aceptort 将name变量写为v1。
第一阶段A:proposer发起prepare(name,n1),n1是递增提议版本号,发送给3个Acceptor,说,我现在要写name这个变量,我的版本号是n1
第一阶段B:Acceptor收到proposer的消息,比对自己内部保存的内容,发现之前name变量(null,null)没有被写入且未收到过提议,都返回给proposer,并在内部记录name这个变量,已经有proposer申请提议了,提议版本号是n1;
第二阶段A:proposer收到3个Acceptor的响应,响应内容都是:name变量现在还没有写入,你可以来写。proposer确认获得超过半数以上Acceptor同意,发起第二阶段写入操作:accept(v1,n1),告诉Acceptor我现在要把name变量协议v1,我的版本号是刚刚获得通过的n1;
第二阶段B:accpetor收到accept(v1,n1),比对自身的版本号是一致的,保存成功,并响应accepted(v1,n1);
结果阶段:proposer收到3个accepted响应都成功,超过半数响应成功,到此name变量被确定为v1。
以上是正常的paxos协议提议确定流程,是不是很简单,很容易理解呢?
确定你理解了上面的例子再往后看。
这是最简单也最容易理解的例子,但真实情况远比这个复杂,还有以下问题:
如果其中的某个Acceptor没响应怎么处理?
如果只写成功了一个accpetor又怎么处理,写成功两个呢?
如果多个proposer并发写会导致accpetor写成不同值吗?
learner角色是做什么用?
为什么是超过半数同意?
paxos特殊情况下的处理
第一种情况:Proposer提议正常,未超过accpetor失败情况
问题:还是上面的例子,如果第二阶段B,只有2个accpetor响应接收提议成功,另外1个没有响应怎么处理呢?
处理:proposer发现只有2个成功,已经超过半数,那么还是认为提议成功,并把消息传递给learner,由learner角色将确定的提议通知给所有accpetor,最终使最后未响应的accpetor也同步更新,通过learner角色使所有Acceptor达到最终一致性。
第二种情况:Proposer提议正常,但超过accpetor失败情况
问题:假设有2个accpetor失败,又该如何处理呢?
处理:由于未达到超过半数同意条件,proposer要么直接提示失败,要么递增版本号重新发起提议,如果重新发起提议对于第一次写入成功的accpetor不会修改,另外两个accpetor会重新接受提议,达到最终成功。
情况再复杂一点:还是一样有3个accpetor,但有两个proposer。
情况一:proposer1和proposer2串行执行
proposer1和最开始情况一样,把name设置为v1,并接受提议。
proposer1提议结束后,proposer2发起提议流程:
第一阶段A:proposer1发起prepare(name,n2)
第一阶段B:Acceptor收到proposer的消息,发现内部name已经写入确定了,返回(name,v1,n1)
第二阶段A:proposer收到3个Acceptor的响应,发现超过半数都是v1,说明name已经确定为v1,接受这个值,不在发起提议操作。
情况二:proposer1和proposer2交错执行
proposer1提议accpetor1成功,但写入accpetor2和accpetor3时,发现版本号已经小于accpetor内部记录的版本号(保存了proposer2的版本号),直接返回失败。
proposer2写入accpetor2和accpetor3成功,写入accpetor1失败,但最终还是超过半数写入v2成功,name变量最终确定为v2;
proposer1递增版本号再重试发现超过半数为v2,接受name变量为v2,也不再写入v1。name最终确定还是为v2
情况三:proposer1和proposer2第一次都只写成功1个Acceptor怎么办
都只写成功一个,未超过半数,那么Proposer会递增版本号重新发起提议,这里需要分多种情况:
3个Acceptor都响应提议,发现Acceptor1{v1,n1} ,Acceptor2{v2,n2},Acceptor{null,null},Processor选择最大的{v2,n2}发起第二阶段,成功后name值为v2;
2个Acceptor都响应提议,
如果是Acceptor1{v1,n1} ,Acceptor2{v2,n2},那么选择最大的{v2,n2}发起第二阶段,成功后name值为v2;
如果是Acceptor1{v1,n1} ,Acceptor3{null,null},那么选择最大的{v1,n1}发起第二阶段,成功后name值为v1;
如果是Acceptor2{v2,n2} ,Acceptor3{null,null},那么选择最大的{v2,n2}发起第二阶段,成功后name值为v2;
只有1个Acceptor响应提议,未达到半数,放弃或者递增版本号重新发起提议
可以看到,都未达到半数时,最终值是不确定的!
整个过程自己也在学习,如有不对的地方欢迎指出:)
收集到一些资料可以分享下,也相当于分享自己的学习过程:
1. 首先,推荐的是知行学社的《分布式系统与Paxos算法视频课程》: ,视频讲的非常好,很适合入门,循序渐进慢慢推导,我自己看了不下5遍,视频讲解理解更深,推荐大家都看看,视频末尾说有后续介绍,一直没有找到,如果有哪位大侠找到了通知下我,不胜感激。
2. 推荐刘杰的《分布式系统原理介绍》 ,里面有关于paxos的详细介绍,例子非常多,也有包括paxos协议的证明过程,大而全,质量相当高的一份学习资料!
3. 推荐的一份高质量ppt《可靠分布式系统基础 Paxos 的直观解释》,虽然是只是一份ppt没有讲解视频,但看ppt也能理解整个的paxos介绍和推导过程,写的很具体,配图很清晰明了;
4. 微信的几篇公众号文章:《微信PaxosStore:深入浅出Paxos算法协议》(微信PaxosStore:深入浅出Paxos算法协议 )、《微信开源:生产级paxos类库PhxPaxos实现原理介绍》(微信自研生产级paxos类库PhxPaxos实现原理介绍 ),文章写的都挺好,但是博文有个缺点是知识比较零散,不适合入门,需要有一定基础才好理解;
5. 技术类的东西怎么能只停留在看上面,肯定要看代码啊,推荐微信开源的phxpaxos:https://github.com/tencent-wechat/phxpaxos,结合代码对协议理解更深,很多时候说了一大堆看代码就是一个if或者for循环,看了代码豁然开朗。
6. 如果英文可以的话,一定要看看paxos作者Lamport《paxos made simple》的论文。
总结
Paxos协议是用来解决分布式系统中一致性问题的其中一种解决方案。协议过程看似羞涩难懂,只要理解accpetor接收阶段的不同处理流程和proposer提议阶段的处理流程,也就基本掌握了paxos协议的精髓,处理流程也不复杂,只是异常条件分支较多,只要一个个去理解也没什么难度,比我们写的业务流程简单多了。
最最后,如果有哪里写的不对的地方,欢迎指出共同学习,共同进步!
---------------------
作者:yinnnnnnn
来源:CSDN
原文:https://blog.csdn.net/qq_35440678/article/details/78080431
版权声明:本文为博主原创文章,转载请附上博文链接!