paxos算法号称是"世界上惟一的分布式一致性算法",其余任何一致性算法都是它的变体.html
最近在看paxos算法, 看了很多博客, 都感受总结得不够到位,甚至有理解误差的地方,却是在博客的引用文章里面找到了一篇英文文献,看完后豁然开朗茅塞顿开.算法
因而把那篇英文原文翻译了一下, 加深一下理解架构
英文文献虽是2012年的了, 可是短小精悍,值得一看,原文地址是:分布式
文章中不全是直译, 有些地方改为了我本身的理解, 因此有可能有理解错的地方, 还望指出.3d
另外在理解的过程当中参考到了如下这篇文章, 也是一篇paxos算法相关的译文cdn
本文经过一个实例描述了一个叫Paxos的分布式一致性算法blog
分布式一致性算法一般是用于让多个计算机节点就某个单值的修改达成一致, 例如事务的提交commit或回滚rollback, 典型的思想就是二阶段提交或三阶段提交.事务
算法并不关心这个单值是什么,只关心最后只有惟一一个值被全部的节点选中, 对该值的修改达成一致
在一个分布式系统中这很是的难, 由于不一样机器以前的消息可能会丢失, 或是被无限延迟, 甚至机器自己也会挂掉
Paxos算法能够保证最终只会有一个值会被选中, 可是不能保证若是集群中的大多数节点挂掉后,还能选中一个值
Paxos的节点能够是proposer, acceptor,learner中的任何一种角色.proposer会提议一个它想被采纳的值, 通常是经过发送一个包含该提议值的提案给集群中的每一个acceptor. 而后acceptor会独立的决定是否接受这个提案--它可能会接收到多个proposer的不一样提案, 决定好后会把它的决定发给learner. learner的做用是判断一个值是否已经被接受.在Paxos算法中, 只有一个值被大多数的acceptor选中, 才算被Paxos算法选中.在实际项目中, 一个节点可能担任多种角色, 可是在这个例子里面, 每一种角色都是一个独立的节点.
图1 Paxos的基本架构. 几个proposer向acceptor提交提案. 当一个acceptor接受了一个值后, 它把它的决定发给learner
在标准的Paxos算法中, 一个proposer会发送两种类型的消息给acceptors: prepare request 和accept request. 在算法的第一阶段, proposer会发送一个prepare request给每个acceptor, 这个prepare request包含一个提议值value和一个提案号number.每个proposer的提案号number必须是正数, 单调递增的,独一无二的天然数[1].
在下面图2的例子中, 有两个proposer, 都在发送prepare request. proposer A的请求([n=2,v=8])比proposer B的请求([n=4,v=5])先到达acceptor X和acceptor Y, 而proposer B的请求先到达acceptor Z
图2: Paxos. proposer A和B各发送了一个prepare request 给每个accetor. 在这个例子中, proposer A的请求先到达acceptor X和Y, 而proposer B的请求先到达了acceptor Z.
若是一个acceptor接收到了一个prepare request而又没接收过其余的提案, 这个acceptor会回应一个prepare response, 并保证不会接受其余比当前提案号number更小的提案. 下面图3展现了每一个acceptor是如何响应它们接收到的prepare request的
图3: 每一个acceptor都对它接收到的第一个prepare request 进行prepare response.
最终, acceptor Z接收到了proposer A的请求[2], acceptor X和Y收到了proposer B的请求.
若是一个acceptor以前已经接收了一个提案号更高的prepare request的话, 那么后面收到的prepare request就会被忽略, 这个例子中就是acceptor Z会忽略掉proposer A的请求(Z已经接收了B的提案n=4).
若是acceptor以前没有接收过更高提案号的提案, 它会保证忽略其余提案号比这个更低的请求(注意是包括prepare request和accept request),而后在prepare response中把它已经选中的提案号最高的提议(包括这个提议的值)发送给proposer.在这个例子就是acceptor X和Y给proposer B的响应(X和Y已经接受了一个B的[n=2,v=8]的提案,当再收到[n=4, v=5]的提案时, 它保证会忽略任何n<4的prepare request和accept request, 而后把[n=2, v=8]的prepare response回去给B)
图4: acceptor Z 忽略了proposer A的请求, 由于它已经接收到了更高的提议号(4 > 2). acceptor X和Y给proposer B响应了它见过最高的提议号的提案, 并承诺会忽略提案号更小的提案
一旦proposer 收到了大多数acceptor的prepare response, 它就能够开始给全部的acceptor发送accept request了. 由于proposer A接收到prepare response中代表在它以前没有更早的提案. 因此它的accept request中的提案号和提议值都是跟prepare request中的同样.然而,这个accept request被全部的acceptor都拒绝了,由于它们都承诺了不会接收提议号比4更新的提案(由于都见过proposer B的提案了)
Proposer B的accept request状况就跟proposer A的有所不一样了. 首先它的提案号仍是它以前的提案号(n=4), 可是提议值却不是它以前的提议值了(它以前提议的是v=5), 而是它在prepare response中接收到的提议值(v=8)[3]
图5: proposer B也发送了一个accept request给每个acceptor.acceptor request中的提案号是它以前的提案号(4), 而提议值是它在prepare response中收到的值(8, 来自proposer A的提案[n=2, v=8])
若是acceptor收到了一个提案号不小于它见过的accept request, 它会接受这个accept request而且发送一个通知给到learner节点. 当learner节点发现大多数acceptor都已经接受了一个值的时候,Paxos算法就认为这个值已经被选中.
当一个值被paxos选中后,后续的流程中将不能改变这个值.例如,当另外一个proposer C发送一个提案号更高的prepare request(例如, [n=6, v=7])过来时,全部的acceptor都会响应它以前已经选中的提议(n=4,v=8).这会要求proposer C在后续的acceptor request中也只能发送[n=6, v=8]的提议, 即只能确认一遍已经选中的这个值. 再后面, 若是有少许的acceptor还没选中一个值的话, 这个流程会保证最终全部的节点都会一致地选中同一个值.