Skip to content

Commit

Permalink
fix typo
Browse files Browse the repository at this point in the history
  • Loading branch information
isno committed Feb 3, 2025
1 parent c4e649f commit eb397c5
Show file tree
Hide file tree
Showing 12 changed files with 101 additions and 108 deletions.
41 changes: 20 additions & 21 deletions .vuepress/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,15 +176,30 @@ export default defineUserConfig({
'/network/conclusion.md',
]
},
{
text: '第四章:负载均衡与代理技术',
link: '/balance/summary.md',
collapsable: false,
sidebarDepth: 1,
children: [
'/balance/balance.md',
'/balance/balance-features.md',
'/balance/balance-topology.md',
'/balance/balance4.md',
'/balance/balance7.md',
'/balance/global-load-balancer.md',
'/balance/conclusion.md',
]
},

{
text: "第四章:数据一致性与分布式事务",
text: "第五章:数据一致性与分布式事务",
link: '/distributed-transaction/summary.md',
children: [
'/distributed-transaction/ACID.md',
'/distributed-transaction/CAP.md',
{
text: "4.3 分布式事务模型",
text: "5.3 分布式事务模型",
link: '/distributed-transaction/transaction.md',
children: [
'/distributed-transaction/BASE.md',
Expand All @@ -197,23 +212,23 @@ export default defineUserConfig({
]
},
{
text: '第五章:分布式共识与算法',
text: '第六章:分布式共识与算法',
collapsable: true,
link: '/consensus/summary.md',
sidebarDepth: 2,
children: [
'/consensus/consensus.md',
'/consensus/Replicated-State-Machine.md',
{
text: "5.3 Paxos 算法",
text: "6.3 Paxos 算法",
link: '/consensus/Paxos.md',
children: [
'/consensus/Paxos-history.md',
'/consensus/Basic-Paxos.md',
]
},
{
text: "5.4 Raft 算法",
text: "6.4 Raft 算法",
link: '/consensus/Raft.md',
children: [
'/consensus/raft-leader-election.md',
Expand All @@ -224,22 +239,6 @@ export default defineUserConfig({
'/consensus/conclusion.md',
]
},
{
text: '第六章:负载均衡与代理技术',
link: '/balance/summary.md',
collapsable: false,
sidebarDepth: 1,
children: [
'/balance/balance.md',
'/balance/balance-features.md',
'/balance/balance-topology.md',
'/balance/balance4.md',
'/balance/balance7.md',
'/balance/global-load-balancer.md',
'/balance/conclusion.md',
]
},

{
text: '第七章:容器编排技术',
link: '/container/summary.md',
Expand Down
47 changes: 22 additions & 25 deletions consensus/Basic-Paxos.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,33 @@
# 5.3.2 Paxos 算法
# 6.3.2 Paxos 算法

希望你没有对前篇 Paxos 的“复杂”做的铺垫所吓倒,共识问题已经算是一个古老的领域,30 余年间已经有无数简洁直白的视频、论文等资料进行过解读[^1]。接下来,我们先了解 Paxos 基本背景,然后直面 Paxos 算法细节,最后再用具体的例子验证 Paxos 算法。
希望你没有对前篇 Paxos 的“复杂”做的铺垫所吓倒,共识问题已经算是一个古老的领域,30 余年间已经有无数简洁直白的视频、论文等资料进行过解读[^1]。接下来,我们先了解 Paxos 基本背景,然后直面 Paxos 算法细节,最后用具体的例子验证 Paxos 算法。

## 1. Paxos 算法背景

在 Paxos 算法中,节点分为下面三种角色:
在 Paxos 算法中,节点分为三种角色。

- **提议者**Proposer):提议者是启动共识过程的节点,它提出一个值,请求其他节点对这个值进行投票,提出值的行为称为发起“提案"(Proposal),提案包含提案编号 (Proposal ID) 和提议的值 (Value)。注意的是,Paxos 算法是一个典型的为“操作转移”模型设计的算法,为简化表述,本文把提案类比成“变量赋值”操作,但你应该理解它是“操作日志”相似的概念,后面介绍的 Raft 算法中,直接就把“提案”称做“日志”了。
- **提议者**Proposer):提议者是启动共识过程的节点,它提出一个值,请求其他节点对这个值进行投票,提出值的行为称为发起“提案"(Proposal),提案包含提案编号 (Proposal ID) 和提议的值 (Value)。注意的是,Paxos 算法是一个典型的为“操作转移”模型设计的算法,为简化表述,本文把提案类比成“变量赋值”操作,但你应该理解它是“操作日志”相似的概念,后面介绍的 Raft 算法中,直接就把“提案”称做“日志”了。
- **决策者**(Acceptor):接受或拒绝提议者发起的提案,如果一个提案被超过半数的决策者接受,意味着提案被“批准”(accepted)。提案一旦被批准,意味着在所有节点中达到共识,便不可改变、永久生效。
- **记录者**(Learner):记录者不发起提案,也不参与决策提案,它们学习、记录被批准的提案。

在 Paxos 算法中,节点都是平等的,它们都可以承担一种或者多种角色。例如,提议者即可发起提案,也可以就一个提案进行表决,但为了 Quorum 的计算更加明确,表决提案的节点数最好是奇数个
在 Paxos 算法中,所有节点都是平等的,能够承担一种或多种角色。例如,提议者既可以发起提案,也可以对其他提案进行表决。但为了更明确地计算 Quorum,通常建议表决提案的节点数为奇数

Paxos 是基于 Quorum 的算法,但“少数服从多数”并不能解决所有的问题。例如,由于并发操作导致的提案冲突。

如图 5-5 所示,S~1~ 向 S~1~、S~2~、S~3~ 发起提案(red)。同时,S~5~ 也向 S~3~、S~4~、S~5~ 发起提案(blue)。它们的提案 Quorum 都达成了,也就是说一个提案有两个值被批准,这显然破坏了一致性原则。
在 Paxos 算法中,所有节点都可以发起提案。如果两个节点同时发起提案,就会导致提案冲突。如图 6-5 所示,S~1~ 向 S~1~、S~2~、S~3~ 发起提案(red)。同时,S~5~ 也向 S~3~、S~4~、S~5~ 发起提案(blue)。它们的提案 Quorum 都达成了,也就是说一个提案有两个值被批准,这显然破坏了一致性原则。

:::center
![](../assets/paxos_2pc_choice.png) <br/>
5-5 网络延迟导致冲突
6-5 网络延迟导致冲突
:::

根据图 5-5,你会发现提案冲突发生在 S~3~,S~3~ 是两个 Quorum 的交集点,它的时间线上有两个不同的值被批准。
根据图 6-5,你会发现提案冲突发生在 S~3~,S~3~ 是两个 Quorum 的交集点,它的时间线上有两个不同的值被批准。

我们知道,设计程序的一个基本常识是,如果多个线程同时操作某个共享变量,一定要加上互斥锁,不然会出现各种意外情况。不难发现,S~3~ 问题的本质是“在分布式环境下并发操作共享变量的问题”。
我们知道,设计程序的一个基本常识是,**如果多个线程同时操作某个共享变量,一定要加上互斥锁,不然会出现各种意外情况**。不难发现,S~3~ 问题的本质是“在分布式环境下并发操作共享变量的问题”。

因为分布式环境下随时可能出现通信故障,我们不能“套用”进程加锁的机制解决 S~3~ 的问题。举个例子,假如一个节点获得锁之后,释放锁之前故障了。那么,整个系统就会被无限期等待阻塞
由于分布式环境中随时可能发生通信故障,我们不能粗暴“套用”进程加锁机制来解决 S~3~ 的问题。举个例子,如果一个节点在获得锁后故障,且在释放锁之前发生故障,整个系统可能会陷入无限期的阻塞状态

解决上述问题的关键在于,得有一种可供其他节点抢占锁的机制,避免因通信故障导致死锁。

笔者在本书第四章 4.2 节 介绍过“乐观锁”。分布式抢占锁的设计思想和“乐观锁”有异曲同工之妙。回顾乐观锁的示例 SQL,WHERE 条件的作用是判断在它操作之前,数据是否被修改。如果修改过,则请求最新的数据,更新版本号,然后用重试的方式再次修改
在本书第五章第 5.2 节中,笔者介绍了“乐观锁”。分布式抢占锁的设计思想与“乐观锁”有异曲同工之妙。回顾乐观锁的示例 SQL,WHERE 条件用于判断在操作之前数据是否已被修改。如果数据已被修改,则请求最新的数据,更新版本号,并通过重试机制再次进行修改

```SQL
UPDATE accounts
Expand All @@ -38,11 +36,11 @@ SET balance = balance + ?,
WHERE id = ? AND version = ?;
```

我们可以借鉴“乐观锁”的思路,尝试解决图 5-5 所示的冲突问题。请看下面的操作:
我们可以借鉴“乐观锁”的思路,尝试解决图 6-5 所示的冲突问题。

首先,S~1~ 发起提案,S~3~ 收到 S~1~ 提案时,应该意识到 S~5~ 发起的提案(blue)的 Quorum 已经达成,S~1~ 提案(red)已经失效。根据先到先得原则,S~1~ 应该更新自己的提案值(red 替换为 blue),这个操作相当于对提案编号(乐观锁中的 version)“锁定”,防止之后出现多个冲突的提案编号。

了解接受了哪些编,接下来的处理就简单了。现在,我们可以直面 Paxos 算法的细节了。
一旦了解了哪些提案被接受,接下来的处理就变得简单了。现在,我们可以直面 Paxos 算法的细节了。

## 2. Paxos 算法描述

Expand All @@ -60,7 +58,7 @@ Paxos 算法的第二个阶段称“批准阶段”(Accept)。提议者向

:::center
![](../assets/paxos.svg) <br/>
5-6 Paxos 算法流程
6-6 Paxos 算法流程
:::

## 3. Paxos 算法验证
Expand All @@ -71,43 +69,42 @@ Paxos 算法的第二个阶段称“批准阶段”(Accept)。提议者向

现在,我们来分析 S~1~ 、S~5~ 同时发起提案,会出现什么情况。

**情况一:提案已批准**。如图 5-7 所示,S~1~ 收到客户端的请求,于是 S~1~ 作为提议者,向 S~1~...S~3~ 广播 Prepare(3.1) 消息,决策者 S~1~...S~3~ 没有接受过任何提案,所以接受该提案。接着,S~1~ 广播 Accept(3.1, X) 消息,提案 X 成功被批准。
**情况一:提案已批准**。如图 6-7 所示,S~1~ 收到客户端的请求,于是 S~1~ 作为提议者,向 S~1~...S~3~ 广播 Prepare(3.1) 消息,决策者 S~1~...S~3~ 没有接受过任何提案,所以接受该提案。接着,S~1~ 广播 Accept(3.1, X) 消息,提案 X 成功被批准。

在提案 X 被批准后,S~5~ 收到客户端的提案 Y,S~5~ 作为提议者向 S~3~...S~5~ 广播 Prepare(4.5) 消息。对 S~3~ 来说,4.5 比 3.1 大,且已经接受了 X,它回复提案 (3.1, X)。S~5~ 收到 S~3~...S~5~ 的回复后,使用 X 替换自己的 Y,接着进入批准阶段,广播 Accept(4.5, X) 消息。S~3~...S~5~ 批准提案,所有决策者就 X 达成一致。

:::center
![](../assets/paxos-p1.png) <br/>
5-7 提案已批准
6-7 提案已批准
:::

**情况二:事实上,对于情况一,也就是“取值为 X”并不是一定需要多数派批准,S~5~ 发起提案时,准备阶段的应答中是否包含了批准过 X 的决策者也影响决策**。如图 5-8 所示,S~3~ 接受了提案 (3.1, X),但 S~1~、S~2~ 还没有收到 Accept(3.1, X) 消息。此时 S~3~、S~4~、S~5~ 收到 Prepare(4.5) 消息,S~3~ 回复已经接受的提案 (3.1, X),S~5~ 将提案值 Y 替换成 X,广播 Accept(4.5, X) 消息给 S~3~、S~4~、S~5~,对 S~3~ 来说,编号 4.5 大于 3.1,所以批准提案 X,最终共识的结果仍然是 X。
**情况二:事实上,对于情况一,也就是“取值为 X”并不是一定需要多数派批准,S~5~ 发起提案时,准备阶段的应答中是否包含了批准过 X 的决策者也影响决策**。如图 6-8 所示,S~3~ 接受了提案 (3.1, X),但 S~1~、S~2~ 还没有收到 Accept(3.1, X) 消息。此时 S~3~、S~4~、S~5~ 收到 Prepare(4.5) 消息,S~3~ 回复已经接受的提案 (3.1, X),S~5~ 将提案值 Y 替换成 X,广播 Accept(4.5, X) 消息给 S~3~、S~4~、S~5~,对 S~3~ 来说,编号 4.5 大于 3.1,所以批准提案 X,最终共识的结果仍然是 X。

:::center
![](../assets/paxos-p2.png) <br/>
5-8 提案部分接受,新提议者可见
6-8 提案部分接受,新提议者可见
:::

**情况三:另外一种可能的情况是 S~5~ 发起提案时,准备阶段的应答中未包含批准过 X 的决策节点**。S~1~ 接受了提案 (3.1, X),S~3~ 先收到 Prepare(4.5) 消息,后收到 Accept(3.1, X) 消息,由于 3.1 小于 4.5,会直接拒绝这个提案。提案 X 没有收到多数的回复,X 提案就被阻止了。提案 Y 顺利通过,整个系统最终对“取值为 Y”达成一致。

:::center
![](../assets/paxos-p3.png) <br/>
5-9 提案部分接受,新提议者不可见
6-9 提案部分接受,新提议者不可见
:::


**情况四:从情况三可以推导出另一种极端的情况**,多个提议者同时发起提案,在准备阶段互相抢占,反复刷新决策者上的提案编号,导致任何一方都无法达到多数派决议,这个过程理论上可以无限持续下去,形成“活锁”(livelock)。

解决这个问题并不复杂,将重试时间随机化,就能减少这种巧合发生。
:::center
![](../assets/paxos-p4.png) <br/>
5-10 出现活锁问题
6-10 出现活锁问题
:::

以上,就是整个 Paxos 算法的工作原理。

Paxos 的价值在于推动了分布式共识算法的发展,但它有以下缺陷:只能处理单一提案,且达成共识至少需要两次网络往返,高并发情况下可能导致活锁。因此,Paxos 算法主要用于理论研究,较少直接应用于工程实践。为了应对多次提案和大规模分布式系统的需求,Lamport 在论文《Paxos Made Simple》中提出了 Paxos 的优化变体 —— Multi Paxos。Multi Paxos 引入了“选主”机制,通过多次运行 Paxos 算法来处理多个提案。
Paxos 算法只能处理单个提案,达成共识至少需要两次网络往返,高并发情况下还可能导致活锁。因此,Paxos 算法主要用于理论研究,很少直接用于工程实践。后来,Lamport 在论文《Paxos Made Simple》中提出了 Paxos 的变体 —— Multi Paxos。Multi Paxos 引入了“选主”机制,通过多轮运行 Paxos 算法来处理多个提案。

不过,Lamport 的论文主要关注的是 Paxos 的算法基础和正确性证明,对于领导者选举以及解决多轮提案的效率问题,并没有给出充分的实现细节。2014 年,斯坦福的学者 Diego Ongaro 和 John Ousterhout 发表了论文《In Search of an Understandable Consensus Algorithm》,该论文基于 Multi Paxos 思想,提出了“选主”、“日志复制”等概念及其实现细节,提出了简化和改进版的 Raft 算法。该论文斩获 USENIX ATC 2014 大会 Best Paper 荣誉,Raft 算法更是成为后来 etcd、Consul 等分布式系统的实现基础。
不过,Lamport 的论文主要聚焦于 Paxos 正确性证明,对于领导者选举、多轮提案并没有给出实现细节。2014 年,斯坦福的学者 Diego Ongaro 和 John Ousterhout 发表了论文《In Search of an Understandable Consensus Algorithm》,该论文基于 Multi Paxos 思想,提出了“选主”、“日志复制”的概念,并给出了详细的实现细节。该论文斩获 USENIX ATC 2014 大会 Best Paper 荣誉,更是成为后来 etcd、Consul 等分布式系统的实现基础。


[^1]: 讲解作者是斯坦福教授 John Ousterhunt,他还指导了 Diego Ongaro 写出了 Raft 的论文。本章配图也多来源于 John Ousterhunt 所发表的内容。
Expand Down
Loading

0 comments on commit eb397c5

Please sign in to comment.