图解 Paxos 算法

👏作者简介:大家好,我是爱写博客的嗯哼,爱好Java的小菜坤

🔥如果感觉博主的文章还不错的话,请👍三连支持👍一下博主哦

📝个人博客:敬请期待

📕系列专栏:面试宝典

前言

Paxos 算法由 Leslie Lamport 在 1989 年提出的一个分布式共识算法,Paxos 算法较难理解,本文尝试以图形化方案解释 Paxos 算法。

本文在很大篇幅参考了韩健极客时间的课程《分布式协议与算法》,有兴趣了解韩老师其他课程的同学可以购买来学习下。

Lamport 提出的 Paxos 算法包括两个部分:

  • Basic Paxos 算法:多节点如何就某个值达成共识
  • Multi Paxos 思想:执行多个 Basic Paxos ,就一系列的值达成共识

一、Basic Paxos

1. 问题

假设一个集群包含三个节点 A, B, C,提供只读< key-value 存储服务。只读 key-value 的意思是指,当一个 key 被创建时,它的值就确定下来了,且后面不能修改。

客户端 1 和客户端 2 同时试图创建一个 X 键。客户端 1 创建值为 "leehao.me" 的 X ,客户端 2 创建值为 "www.leehao.me" 的 X 。在这种情况下,集群如何达成共识,实现各节点上 X 的值一致呢?

2. Paxos 涉及的概念

在 Paxos 算法中,存在提议者(Proposer),接受者(Acceptor),学习者(Learner)三种角色,它们的关系如下:

  • 提议者(Proposer):提议一个值,用于投票表决,可以将上图客户端 1 和客户端 2 看作提议者。实际上,提议者更多是集群内的节点,这里为了演示的方便,将客户端 1 和 2 看作提议者,不影响 Paxos 算法的实质
  • 接受者(Acceptor):对每个提议的值进行投票,并存储接受的值,例如,上图集群内的节点 A、B、C
  • 学习者(Learner):被告知投票的结果,接受达成共识的值,不参与投票的过程,存储接受数据

需要指出的是,一个节点,既可以是提议者,也可以是接受者。

在 Paxos 算法中,使用提案表示一个提议,提案包括提案编号和提议的值。接下来,我们使用 [n, v] 表示一个提案,其中, n 是提案编号, v 是提案的值。

在 Basic Paxos 中,集群中各个节点为了达成共识,需要进行 2 个阶段的协商,即准备(Prepare)阶段和接受(Accept)阶段。

3. 准备阶段

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

客户端作为提议者,向所有的接受者发送包含提案编号的准备请求。注意在准备阶段,请求中不需要指定提议的值,只需要包含提案编号即可。

接下来,节点 A,B 接收到客户端 1 的准备请求(提案编号为 1),节点 C 接收到客户端 2 的准备请求(提案编号为 5)。

集群中各个节点在接收到第一个准备请求的处理:

  • 节点 A, B:由于之前没有通过任何提案,所以节点 A,B 将返回"尚无提案"的准备响应,并承诺以后不再响应提案编号小于等于 1 的准备请求,不会通过编号小于 1 的提案
  • 节点 C:由于之前没有通过任何提案,所以节点 C 将返回"尚无提案"的准备响应,并承诺以后不再响应提案编号小于等于 5 的准备请求,不会通过编号小于 5 的提案

接下来,当节点 A,B 接收到提案编号为 5 的准备请求,节点 C 接收到提案编号为 1 的准备请求:

  • 节点 A, B:由于提案编号 5 大于之前响应的准备请求的提案编号 1,且节点 A, B 都没有通过任何提案,故均返回"尚无提案"的响应,并承诺以后不再响应提案编号小于等于 5 的准备请求,不会通过编号小于 5 的提案
  • 节点 C:由于节点 C 接收到提案编号 1 小于节点 C 之前响应的准备请求的提案编号 5 ,所以丢弃该准备请求,不作响应

4. 接受阶段

Basic Paxos 算法第二阶段为接受阶段。当客户端 1,2 在收到大多数节点的准备响应之后会开始发送接受请求。

  • 客户端 1:客户端 1 接收到大多数的接受者(节点 A, B)的准备响应后,根据响应中的提案编号最大的提案的值,设置接受请求的值。由于节点 A, B 均返回"尚无提案",即提案值为空,故客户端 1 把自己的提议值 "leehao.me" 作为提案的值,发送接受请求 [1, "leehao.me"]
  • 客户端 2:客户端 2 接收到大多数接受者的准备响应后,根据响应中的提案编号最大的提案的值,设置接受请求的值。由于节点 A, B, C 均返回"尚无提案",即提案值为空,故客户端 2 把自己的提议值 "www.leehao.me" 作为提案的值,发送接受请求 [5, "www.leehao.me"]

当节点 A, B, C 接收到客户端 1, 2 的接受请求时,对接受请求进行处理:

  • 节点 A, B, C 接收到接受请求 [1, "leehao.me"] ,由于提案编号 1 小于三个节点承诺可以通过的最小提案编号 5,所以提案 [1, "leehao.me"] 被拒绝
  • 节点 A, B, C 接收到接受请求 [5, "www.leehao.me"],由于提案编号 5 不小于三个节点承诺可以通过的最小提案编号 5 ,所以通过提案 [5, "www.leehao.me"],即三个节点达成共识,接受 X 的值为 "www.leehao.me"

如果集群中还有学习者,当接受者通过一个提案,就通知学习者,当学习者发现大多数接受者都通过了某个提案,那么学习者也通过该提案,接受提案的值。

5. 接受者存在已通过提案的情况

上面例子中,准备阶段和接受阶段均不存在接受者已经通过提案的情况。这里继续使用上面的例子,不过假设节点 A, B 已通过提案 [5, "www.leehao.me"],节点 C 未通过任何提案。 增加一个新的提议者客户端 3,客户端 3 的提案为 [9,"leehao"] 。

接下来,客户端 3 执行准备阶段和接受阶段。

客户端 3 向节点 A, B, C 发送提案编号为 9 的准备请求:

节点 A, B 接收到客户端 3 的准备请求,由于节点 A, B 已通过提案 [5, "www.leehao.me"],故在准备响应中,包含此提案信息。

节点 C 接收到客户端 3 的准备请求,由于节点 C 未通过任何提案,故节点 C 将返回"尚无提案"的准备响应。

客户端 3 接收到节点 A, B, C 的准备响应后,向节点 A, B, C 发送接受请求。这里需要特点指出,客户端 3 会根据响应中的提案编号最大的提案的值,设置接受请求的值。由于在准备响应中,已包含提案 [5, "www.leehao.me"],故客户端 3 将接受请求的提案编号设置为 9,提案值设置为 "www.leehao.me" 即接受请求的提案为 [9, "www.leehao.me"]:

节点 A, B, C 接收到客户端 3 的接受请求,由于提案编号 9 不小于三个节点承诺可以通过的最小提案编号,故均通过提案 [9, www.leehao.me]。

概括来说,Basic Paxos 具有以下特点:

  • Basic Paxos 通过二阶段方式来达成共识,即准备阶段和接受阶段
  • Basic Paxos 除了达成共识功能,还实现了容错,在少于一半节点出现故障时,集群也能工作
  • 提案编号大小代表优先级。对于提案编号,接受者提供三个承诺:
    • 如果准备请求的提案编号,小于等于接受者已经响应的准备请求的提案编号,那么接受者承诺不响应这个准备请求
    • 如果接受请求中的提案编号,小于接受者已经响应的准备请求的提案编号,那么接受者承诺不通过这个提案
    • 如果按受者已通过提案,那些接受者承诺会在准备请求的响应中,包含已经通过的最大编号的提案信息

二、Multi Paxos

Basic Paxos 算法只能对单个值达成共识,对于多个值的情形,Basic Paxos 算法就不管用了。因此,Basic Paxos 算法几乎只是用来理论研究,并不直接应用在实际工作中。

Lamport 提出的 Multi Paxos 是一种思想,并不是算法。

Multi Paxos 算法则是一个统称,是指基于 Multi Paxos 思想,通过多个 Basic Paxos 实例实现一系列值的共识的算法(例如 Raft 算法等)。

如果直接通过多次执行 Basic Paxos 实例方式,来实现一系列值的共识,存在以下问题:

  • 如果集群中多个提议者同时在准备阶段提交提案,可能会出现没有提议者接收到大多数准备响应,导致需要重新提交准备请求。例如,在一个 5 个节点的集群中,有 3 个节点同时作为提议者同时提交提案,那就会出现没有一个提议者获取大多数的准备响应,而需要重新提交
  • 为了达成一个值的共识,需要进行 2 轮 RPC 通讯,分别是准备阶段和接受阶段,性能低下

为了解决以上问题,Multi Paxos 引入了领导者(Leader)和优化了 Basic Paxos 的执行过程。

1. 领导者

上面的问题一存在多个提议者同时提交准备请求的情况,如果引入了领导者,由领导者作为唯一的提议者,就可以解决问题一中的冲突的问题。

Lamport 没有说明如何选举领导者,需要在实现 Multi Paxos 算法的时候自行实现。这里我们略去如何选举领导者的算法,假设已经选举出领导者。

2. 优化 Basic Paxos 执行过程

准备阶段的意义,是发现接受者节点上已通过的提案的值。引入领导者后,只有领导者才可发送提议,因此,领导者的提案就已经是最新的了,不再需要通过准备阶段来发现之前被大多数节点通过的提案,领导者可以独立指定提议的值。

这样一来,准备阶段存在就没有意义了,领导者可以直接跳过准备阶段,直接进行接受阶段,减少了 RPC 通讯次数。

3. Chubby 的 Multi Paxos 实现

Google 分布式锁 Chubby 实现了 Multi Paxos 算法。Chubby 的 Multi Paxos 算法主要包括:

  • Chubby 引入主节点作为领导者,即主节点作为唯一提议者,不存在多个提议者同时提交提案的情况,也不存在提案冲突的情况。Chubby 通过执行 Basic Paxos 算法进行投票选举产生主节点
  • 在 Chubby 中,由于引入了主节点,因此,也去除了 Basic Paxos 的准备阶段
  • 在 Chubby 中,为实现强一致性,所有的读请求和写请求都由主节点来处理
  1. Chubby 所有的写请求由主节点来处理

当主节点接收到客户端的写请求,作为提议者,将数据发送给所有节点,在大多数服务器接受了这个写请求后,给客户端响应写成功。

  1. Chubby 所有的读请求由主节点来处理

当主节点接收到读请求,主节点只需要查询本地数据,然后返回给客户端。

另外,需要指出的是,Basic Paxos 是经过证明的算法。Multi Paxos 是一种思想但缺乏实现算法所需的编程细节,因此,Multi Paxos 的算法实现,是建立在一个未经证明的基础之上。实现 Multi Paxos 算法,最大的挑战是如何证明它是正确的。

三、参考资料

  1. time.geekbang.org/column/arti...
  2. blog.the-pans.com/paxos-expla...
  3. zhuanlan.zhihu.com/p/31780743
  4. www.cnblogs.com/linbingdong...
  5. www.ux.uis.no/~meling/pap...
  6. medium.com/@nevverland...
  7. www.read.seas.harvard.edu/~kohler/cla...
  8. lamport.azurewebsites.net/pubs/lampor...
  9. lamport.azurewebsites.net/pubs/paxos-...

结语

每个人都有自己独特的才华和潜能,在这个广袤的世界上,你的存在是有意义的。无论你是谁,你的背景如何,你所处的环境怎样,只要你敢于跨出舒适区,付出努力,追求卓越,你就能够开创属于自己的辉煌。

我们下期见。

每一次努力都是一次进步,即使进展缓慢,也要坚持不懈。

往期文章推荐

相关推荐
Asthenia041237 分钟前
Spring扩展点与工具类获取容器Bean-基于ApplicationContextAware实现非IOC容器中调用IOC的Bean
后端
bobz9651 小时前
ovs patch port 对比 veth pair
后端
Asthenia04121 小时前
Java受检异常与非受检异常分析
后端
uhakadotcom1 小时前
快速开始使用 n8n
后端·面试·github
JavaGuide1 小时前
公司来的新人用字符串存储日期,被组长怒怼了...
后端·mysql
bobz9652 小时前
qemu 网络使用基础
后端
Asthenia04122 小时前
面试攻略:如何应对 Spring 启动流程的层层追问
后端
Asthenia04122 小时前
Spring 启动流程:比喻表达
后端
Asthenia04123 小时前
Spring 启动流程分析-含时序图
后端
ONE_Gua3 小时前
chromium魔改——CDP(Chrome DevTools Protocol)检测01
前端·后端·爬虫