Paxos问题是指分布式的系统中存在故障(fault),但不存在恶意(corrupt)节点场景(即可能消息丢失或重复)下的共识达成(Consensus)问题。因为最早是Leslie Lamport用Paxon岛的故事模型来进行描述而命名。
故事背景是古希腊Paxon岛上的多个法官在一个大厅内对一个议案进行表决,如何达成统一的结果。他们之间通过服务人员来传递纸条,但法官可能离开或进入大厅,服务人员可能偷懒去睡觉。
Paxos是第一个被证明的共识算法,其原理基于两阶段提交并进行扩展。
算法中将节点分为三种类型:
并且,算法需要满足safety和liveness两方面的约束要求(实际上这两个基础是大部分分布式算法都该考虑的):
safety:保证决议结果是对的,无歧义的,不会出现错误情况。
基本过程包括proposer提出提案,先争取大多数acceptor的支持,超过一半支持时,则发送结案结果给所有人进行确认。一个潜在的问题是proposer在此过程中出现故障,可以通过超时机制来解决。极为凑巧的情况下,每次新的一轮提案的proposer都恰好故障,系统则永远无法达成一致(概率很小)。
Paxos能保证在超过1/2的正常节点存在时,系统能达成共识。
读者可以试着自己设计一套能达成共识的方案,会发现在满足各种约束情况下,算法自然就会那样设计。
单个提案者+多个接收者
如果系统中限定只有某个特定节点是提案者,那么一致性肯定能达成(只有一个方案,要么达成,要么失败)。提案者找收到来自多数接收者的投票,即可认为通过,因为系统中不存在其他的提案。
但一旦提案者故障,则系统无法工作。
多个提案者+单个接收者
限定某个节点作为接收者。这种情况下,共识也很容易达成,接收者收到多个提案,选第一个提案作为决议,拒绝掉后续的提案即可。
缺陷也是容易发生单点故障,包括接收者故障或首个提案者节点故障。
以上两种情形其实类似主从模式,虽然不那么可靠,但因为原理简单而被广泛采用。当提案者和接收者都推广到多个情形,会出现一些挑战。
多个提案者+多个接收者
既然限定单提案者或单接收者都会出现故障,那么就得允许出现多个提案者和多个接收者。问题一下子变得复杂了。
一种情况是同一时间片段(如一个提案周期)内只有一个提案者,这时可以退化到单提案者的情形。需要设计一种机制来保障提案者的正确产生,例如按照时间、序列、或者大家猜拳(出一个数字来比较)之类。考虑到分布式系统要处理的工作量很大,这个过程要尽量高效,满足这一条件的机制非常难设计。
另一种情况是允许同一时间片段内可以出现多个提案者。那同一个节点可能收到多份提案,怎么对他们进行区分呢?这个时候采用只接受第一个提案而拒绝后续提案的方法也不适用。很自然的,提案需要带上不同的序号。节点需要根据提案序号来判断接受哪个。比如接受其中序号较大(往往意味着是接受新提出的,因为旧提案者故障概率更大)的提案。
如何为提案分配序号呢?一种可能方案是每个节点的提案数字区间彼此隔离开,互相不冲突。为了满足递增的需求可以配合用时间戳作为前缀字段。
此外,提案者即便收到了多数接收者的投票,也不敢说一定通过。因为在此过程中系统可能还有其他的提案。
两阶段提交
提案者发出提案之后,收到一些反馈。一种结果是自己的提案被大多数接受了,另一种结果是没被接受。没被接受的话好说,过会再试试。
即便收到来自大多数的接受反馈,也不能认为就最终确认了。因为这些接收者自己并不知道自己刚反馈的提案就恰好是全局的绝大多数。
很自然的,引入了新的一个阶段,即提案者在前一阶段拿到所有的反馈后,判断这个提案是可能被大多数接受的提案,需要对其进行最终确认。
Paxos里面对这两个阶段分别命名为准备(prepare)和提交(commit)。准备阶段解决大家对哪个提案进行投票的问题,提交阶段解决确认最终值的问题。
准备阶段:
一旦多数接受了共同的提案值,则形成决议,成为最终确认的提案。