一、简介

Paxos 协议是少数在工程实践中证实的强一致性、高可用的去中心化分布式协议。Google 的很多大型分布式系统都采用了 Paxos 算法来解决分布式一致性问题,如 Chubby、Megastore 以及 Spanner 等。开源的 ZooKeeper 以及 MySQL 5.7 推出的用来取代传统的主从复制的 MySQL Group Replication 等纷纷采用 Paxos 算法解决分布式一致性问题。

Paxos 协议的流程较为复杂,但其基本思想却不难理解,类似于人类社会的投票过程。Paxos 协议中,有一组完全对等的参与节点,这组节点各自就某一事件做出决议,如果某个决议获得了超过半数节点的同意则生效。Paxos 协议中只要有超过一半的节点正常,就可以工作,能很好对抗宕机、网络分化等异常情况。

二、协议角色

Proposer:提案者。Proposer 可以有多个,Proposer 提出议案(value)。所谓 value,在工程中可以是任何操作,例如“修改某个变量的值为某个值”、“设置当前 primary 为某个节点”等等。 Paxos协议中统一将这些操作抽象为 value,同一轮 Paxos过程,最多只有一个 value 被批准。

Acceptor:批准者。Acceptor 有 N 个,Proposer 提出的 value 必须获得超过半数(N/2+1)的 Acceptor 批准后才能通过。Acceptor 之间完全对等独立。

Learner:学习者。不参与决策,学习被批准的 value(即获得 N/2 + 1 的 Acceptor 批准)。所谓学习就是通过读取各个 Proposer/Acceptor 对 value 的选择结果,如果某个 value 被超过半数 Proposer 通过,则 Learner 学习到了这个 value。

上述三类角色只是逻辑上的划分,实践中一个节点可以同时充当这三类角色。

三、协议流程

Paxos协议解决的是一个分布式系统中的各个进程如何就某个值(决议)达成一致的问题。

Paxos 协议一轮一轮的进行,每轮都有一个编号。每轮 Paxos 协议可能会批准一个 value,也可能无法批准一个 value。 如果某一轮 Paxos 协议批准了某个 value,则以后各轮 Paxos 只能批准这个 value (这是整个协议正确性的基础)。

上述各轮协议流程组成了一个 Paxos 协议实例,即一次 Paxos 协议实例只能批准一个 value,这也是 Paxos 协议强一致性的重要体现。

每轮 Paxos 协议分为准备阶段和批准阶段,在这两个阶段 Proposer 和 Acceptor 有各自的处理流程:
image.png

协议过程举例

image.png

目标: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。

四、Multi-Paxos 算法

Paxos 协议引入了轮数的概念,高轮数的 Paxos 提案可以抢占低轮数的 Paxos 提案,从而避免了死锁的发生。然而这种设计却引入了“活锁”的可能,即 Proposer 相互不断以更高的轮数提出议案,使得每轮 Paxos过程都无法最终完成,从而无法批准任何一个value。Multi-Paxos 正是为解决此问题而提出,Multi-Paxos 基于Basic Paxos 做了两点改进:

  1. 针对每一个要确定的值,运行一次 Paxos 算法实例(Instance),形成决议。每一个 Paxos 实例使用唯一的 Instance ID 标识。
  2. 在所有 Proposers 中选举一个 Leader,由 Leader 唯一的提交 Proposal 给 Acceptors 进行表决。这样没有 Proposer 竞争,解决了活锁问题。在系统中仅有一个 Leader 进行 value 提交的情况下,Prepare 阶段就可以跳过,从而将两阶段变为一阶段,提高效率。

image.png
Multi-Paxos 首先需要选举 Leader,Leader 的确定也是一次决议的形成,所以可执行一次 Basic Paxos 实例来选举出一个 Leader。选出 Leader 之后只能由 Leader 提交 Proposal,在 Leader 宕机之后服务临时不可用,需要重新选举 Leader 继续服务。在系统中仅有一个 Leader 进行 Proposal 提交的情况下,Prepare 阶段可以跳过。

Multi-Paxos 通过改变 Prepare 阶段的作用范围至后面 Leader 提交的所有实例,从而使得 Leader 的连续提交只需要执行一次 Prepare 阶段,后续只需要执行 Accept 阶段,将两阶段变为一阶段,提高了效率。为了区分连续提交的多个实例,每个实例使用一个 Instance ID 标识,Instance ID 由 Leader 本地递增生成即可。

Multi-Paxos 允许有多个自认为是 Leader 的节点并发提交 Proposal 而不影响其安全性,这样的场景即退化为 Basic Paxos。

Chubby 和 Boxwood 均使用 Multi-Paxos。ZooKeeper 使用的 Zab 也是 Multi-Paxos 的变形。

Paxos 协议简单介绍
理解这两点,也就理解了paxos协议的精髓