分布式 — Paxos 算法

Paxos 用于达成共识性问题,即对多个节点产生的值,该算法能保证只选出唯一一个值。

假设要实现一个分布式集群,这个集群由节点 A、B、C 组成,提供只读 KV 存储服务。一个节点创建只读变量后就不能再进行修改了,所以所有节点必须要先对只读变量的值达成共识,然后所有节点再一起创建这个只读变量。

那么当有多个客户端访问该集群时,试图创建一个只读变量,客户端 1 试图创建值为 3 的 X,客户端 2 试图创建值为 7 的 X,这样要如何达成共识,实现各节点上 X 值的一致呢?

一、角色

Paxos 中,有三种角色,一个完整的算法过程是由这三种角色对应的功能组成的。

  • 提议者(Proposer):提议一个值,用于投票表决。可以将客户端看成提议者。
  • 接受者(Acceptor):对每个提议的值进行投票,并存储接受的值,比如 A、B、C 三个节点。
  • 学习者(Learner):被告知投票的结果,接受达成共识的值,存储保存,不参与投票的过程。一般来说,学习者是数据备份节点,比如 「Master-Slave」模型中的 Slave,被动地接受数据,容灾备份。

二、如何达成共识?

共识协商是分 2 个阶段进行的。

假设客户端 1 的提案编号为 1,客户端 2 的提案编号为 5,并假设节点 A、B 先收到来自客户端 1 的准备请求,节点 C 先收到来自客户端 2 的准备请求。

1. 准备(Prepare)阶段

首先客户端 1、2 作为提议者,分别向所有接受者发送包含提案编号的 准备请求:

在准备请求中是不需要指定提议的值的,只需要携带提案编号就可以了。

当节点 A、B 收到提案编号为 1 的准备请求,节点 C 收到提案编号为 5 的准备请求 后,将进行这样的处理:

由于之前没有通过任何提案,所以节点 A、B 将返回一个 「尚无提案」的响应。也就是说节点 A 和 B 在告诉提议者,我之前没有通过任何提案呢,并承诺以后不再响应提案编 号小于等于 1 的准备请求,不会通过编号小于 1 的提案。

节点 C 也是如此,它将返回一个「尚无提案」的响应,并承诺以后不再响应提案编号小于等于 5 的准备请求,不会通过编号小于 5 的提案。

另外,当节点 A、B 收到提案编号为 5 的准备请求,和节点 C 收到提案编号为 1 的准备请求的时候,将进行这样的处理过程:

当节点 A、B 收到提案编号为 5 的准备请求的时候,因为提案编号 5 大于它们之前响应 的准备请求的提案编号 1,而且两个节点都没有通过任何提案,所以它将返回一个「尚无提案」的响应,并承诺以后不再响应提案编号小于等于 5 的准备请求,不会通过编号小于 5 的提案。

当节点 C 收到提案编号为 1 的准备请求的时候,由于提案编号 1 小于它之前响应的准备请求的提案编号 5,所以丢弃该准备请求,不做响应。

参考