分布式一致性算法详解:从 2PC、3PC 到 Paxos、Raft、ZAB

在单机系统里,"一致性"通常意味着一次写入要么成功、要么失败,读到的数据应该符合预期。但在分布式系统中,数据被拆分到多台机器上,节点可能宕机,网络可能延迟、丢包、分区,消息可能乱序到达。此时,"让多个节点对同一件事达成一致"就变成了一个核心难题。

分布式一致性算法的目标,就是在不可靠的网络和节点环境中,让多个副本尽可能可靠地就某个值、某个日志顺序、某个事务结果达成一致。


一、为什么需要分布式一致性

典型场景包括:

  • 分布式数据库主从复制
  • 分布式事务提交
  • 配置中心的配置变更
  • 注册中心的服务上下线
  • 分布式锁
  • 元数据管理
  • 多副本日志复制
  • 分布式文件系统 Master 高可用

假设有三个节点 A、B、C,它们都保存用户余额:

text 复制代码
A: balance = 100
B: balance = 100
C: balance = 100

现在用户转出 30 元,A 已经更新为 70,但 B、C 还没来得及更新。如果此时系统对外提供读服务,就可能读到不同结果。

这就是分布式系统里的核心问题:多个副本如何保持一致。


二、一致性的不同层次

1. 强一致性

强一致性要求一次写入成功后,后续所有读都能读到最新值。

例如:

text 复制代码
写入 x = 1 成功
之后任意节点读取 x,都必须返回 1

强一致性的用户体验最好,但实现成本最高,通常会牺牲可用性或性能。

2. 最终一致性

最终一致性允许短时间内不同节点看到不同数据,但只要没有新的写入,系统最终会收敛到相同状态。

例如:

text 复制代码
A 节点已经更新
B、C 节点稍后同步
最终 A、B、C 数据一致

DNS、缓存系统、很多互联网业务系统都大量使用最终一致性。

3. 线性一致性

线性一致性是强一致性的一种严格形式。它要求所有操作看起来像是按照某个全局顺序依次执行,并且这个顺序符合真实时间。

如果操作 A 在操作 B 开始前已经完成,那么所有节点都必须认为 A 发生在 B 之前。

Raft、Paxos 这类共识算法通常追求的就是线性一致的日志复制。


三、CAP 理论

CAP 理论指出,在分布式系统中,以下三者不能同时完全满足:

  • Consistency:一致性
  • Availability:可用性
  • Partition Tolerance:分区容错性

网络分区在分布式系统中无法彻底避免,所以实际系统通常必须在 CP 和 AP 之间取舍。

CP 系统

CP 系统优先保证一致性和分区容错性。

当网络分区发生时,为了避免数据冲突,一部分节点可能拒绝服务。

代表系统:

  • ZooKeeper
  • etcd
  • Consul 的一致性存储部分
  • HBase 的强一致元数据管理

AP 系统

AP 系统优先保证可用性和分区容错性。

当网络分区发生时,各分区仍然可以处理请求,但后续需要通过冲突合并、版本比较等方式实现最终一致。

代表系统:

  • Cassandra
  • DynamoDB 的部分设计思想
  • Riak
  • CouchDB

四、2PC:两阶段提交

2PC,全称 Two-Phase Commit,是经典的分布式事务提交协议。

它主要解决的问题是:多个参与者要么全部提交,要么全部回滚。

阶段一:Prepare

协调者询问所有参与者是否可以提交事务。

text 复制代码
Coordinator -> Participant A: Can commit?
Coordinator -> Participant B: Can commit?
Coordinator -> Participant C: Can commit?

参与者执行本地预提交操作,锁定资源,然后回复:

text 复制代码
YES / NO

阶段二:Commit / Rollback

如果所有参与者都返回 YES,协调者发送 COMMIT。

只要有一个参与者返回 NO,协调者发送 ROLLBACK。

text 复制代码
所有人 YES -> COMMIT
任意人 NO -> ROLLBACK

2PC 的优点

  • 模型简单
  • 容易理解
  • 能保证事务原子性
  • 适合传统数据库 XA 事务场景

2PC 的缺点

2PC 最大的问题是阻塞。

如果协调者在第二阶段宕机,参与者可能已经进入 prepared 状态,并且不知道最终应该提交还是回滚。

此时参与者为了保证一致性,只能继续阻塞等待协调者恢复。

text 复制代码
Participant A: 已 prepared,但不知道最终结果
Participant B: 已 prepared,但不知道最终结果
Coordinator: 宕机

这会导致资源长时间被锁住,影响系统可用性。


五、3PC:三阶段提交

3PC,全称 Three-Phase Commit,是对 2PC 的改进。

它将 2PC 的提交过程拆成三个阶段:

  1. CanCommit
  2. PreCommit
  3. DoCommit

3PC 的核心思路

3PC 在提交前增加了一个 PreCommit 阶段,试图减少 2PC 中参与者长时间阻塞的问题。

流程大致如下:

text 复制代码
CanCommit: 询问是否可以提交
PreCommit: 通知即将提交
DoCommit: 正式提交

3PC 的优点

  • 相比 2PC,阻塞风险降低
  • 引入超时机制后,参与者可以在部分场景下自行决策

3PC 的缺点

3PC 依然不能完美解决网络分区问题。

如果发生网络分区,不同节点可能基于超时做出不同决策,导致一致性被破坏。

因此,3PC 在真实工程系统中使用并不多。


六、Paxos:经典共识算法

Paxos 是分布式一致性领域最著名、也最难理解的算法之一。

它解决的问题是:在多个可能失败的节点之间,对某个值达成一致。

Paxos 中有三个角色:

  • Proposer:提议者,提出某个值
  • Acceptor:接受者,对提案投票
  • Learner:学习者,学习最终被选定的值

一个节点可以同时扮演多个角色。

Paxos 的基本约束

Paxos 希望满足:

  1. 只能有一个值最终被选定
  2. 被选定的值必须是某个 Proposer 提出的值
  3. 一旦某个值被选定,所有 Learner 最终都能学习到这个值
  4. 少数节点故障不影响整体决策,只要多数派可用

多数派机制

Paxos 依赖多数派 Quorum。

如果有 5 个节点,那么多数派至少是 3 个。

任何两个多数派一定有交集。

text 复制代码
多数派 1: A B C
多数派 2: C D E

交集: C

这个交集非常关键。它保证后续提案可以知道之前可能已经被接受的值,从而避免多个值同时被选定。

Paxos 两个阶段

第一阶段:Prepare / Promise

Proposer 生成一个全局递增的提案编号 n,向多数 Acceptor 发送 Prepare 请求。

text 复制代码
Prepare(n)

Acceptor 收到后,如果 n 大于它见过的所有提案编号,就承诺:

  • 不再接受编号小于 n 的提案
  • 返回自己曾经接受过的最大编号提案和值

这叫 Promise。

第二阶段:Accept / Accepted

Proposer 收到多数派 Promise 后,根据规则选择值:

  • 如果没有 Acceptor 返回已接受的值,可以使用自己的值
  • 如果有 Acceptor 返回已接受的值,必须选择编号最大的那个已接受值

然后 Proposer 向多数 Acceptor 发送 Accept 请求。

text 复制代码
Accept(n, value)

Acceptor 如果没有承诺过更大的编号,就接受该提案。

当某个值被多数 Acceptor 接受时,这个值就被选定。

Paxos 的优点

  • 理论严谨
  • 能容忍少数节点故障
  • 基于多数派保证一致性
  • 是很多共识算法的理论基础

Paxos 的缺点

  • 难理解
  • 难实现
  • 工程落地复杂
  • 原始 Paxos 只决定一个值,实际系统需要 Multi-Paxos 来复制日志

七、Multi-Paxos

单次 Paxos 只能对一个值达成一致。

但真实系统通常需要对一系列操作达成一致,例如:

text 复制代码
log[1] = set x = 1
log[2] = set y = 2
log[3] = delete z

Multi-Paxos 就是把 Paxos 扩展到多条日志。

它通常会选出一个稳定 Leader,由 Leader 负责连续发起提案。

这样可以减少 Prepare 阶段的开销,提高性能。

Multi-Paxos 的核心优化

普通 Paxos 每次提交都需要两轮通信:

text 复制代码
Prepare -> Promise
Accept  -> Accepted

Multi-Paxos 在 Leader 稳定的情况下,可以复用 Leader 身份,后续日志只需要 Accept 阶段。

text 复制代码
Accept -> Accepted

这让它更适合工程系统。


八、Raft:更容易理解的共识算法

Raft 的目标是提供一个比 Paxos 更容易理解、也更容易实现的共识算法。

很多现代分布式系统使用 Raft,例如:

  • etcd
  • Consul
  • TiKV
  • Nacos 部分一致性实现
  • CockroachDB 的部分复制机制

Raft 把共识问题拆成三个子问题:

  1. Leader 选举
  2. 日志复制
  3. 安全性保证

九、Raft 的角色

Raft 中每个节点有三种状态:

  • Leader:领导者,处理客户端请求并复制日志
  • Follower:跟随者,被动接收 Leader 消息
  • Candidate:候选者,发起选举

正常情况下,一个 Raft 集群只有一个 Leader。

text 复制代码
Client -> Leader -> Followers

十、Raft Leader 选举

Raft 使用任期 term 来区分不同选举周期。

每个节点启动时都是 Follower。

如果 Follower 在 election timeout 时间内没有收到 Leader 的心跳,就会变成 Candidate,并发起选举。

选举流程:

  1. 当前节点 term + 1
  2. 将自己变成 Candidate
  3. 给自己投票
  4. 向其他节点发送 RequestVote
  5. 获得多数票后成为 Leader

为什么需要随机超时

如果所有节点同时超时,就会同时发起选举,导致票数分散。

Raft 使用随机 election timeout,降低选票冲突概率。

text 复制代码
Node A timeout: 150ms
Node B timeout: 230ms
Node C timeout: 310ms

通常最早超时的节点会先发起选举,并更容易成为 Leader。


十一、Raft 日志复制

客户端写请求会先发送给 Leader。

Leader 将操作追加到自己的日志中,然后并行发送给 Followers。

text 复制代码
Client -> Leader: set x = 1
Leader append log
Leader -> Followers: AppendEntries
Followers append log
Followers -> Leader: success
Leader receives majority success
Leader commits log
Leader applies to state machine

只要日志被多数节点复制成功,Leader 就可以提交该日志。

已提交日志

一条日志被多数节点保存后,就可以认为是 committed。

提交后,Leader 会把这条日志应用到状态机,并通过后续心跳通知 Followers 也提交。

text 复制代码
log[8] copied to A, B, C
5 节点集群中已有 3 个节点保存
log[8] committed

十二、Raft 的安全性

Raft 通过几个规则保证安全。

1. Leader 只追加日志

Leader 不会覆盖或删除自己的日志,只会追加新日志。

2. 日志匹配原则

如果两个日志条目拥有相同的 index 和 term,那么它们之前的所有日志也完全相同。

text 复制代码
log[5].term = 3
如果两个节点的 log[5] 都是 term 3
那么 log[1..5] 都应该一致

3. Leader 完整性

如果某条日志已经在某个任期被提交,那么之后所有 Leader 都必须包含这条日志。

这是 Raft 能够保证已提交数据不丢失的关键。


十三、ZAB:ZooKeeper 的一致性协议

ZAB,全称 ZooKeeper Atomic Broadcast,是 ZooKeeper 使用的一致性协议。

ZAB 和 Raft 很相似,也依赖 Leader 和多数派机制。

ZooKeeper 的数据更新必须经过 Leader,然后广播给 Followers。

ZAB 的核心目标

ZAB 主要保证:

  • 原子广播
  • 全局有序
  • 崩溃恢复
  • Leader 切换后数据不丢失

ZAB 的基本流程

  1. Client 向 ZooKeeper 发起写请求
  2. 请求转发给 Leader
  3. Leader 生成事务 Proposal
  4. Leader 广播 Proposal 给 Followers
  5. 多数 Followers 返回 ACK
  6. Leader 发送 COMMIT
  7. 各节点应用事务
text 复制代码
Client -> Leader
Leader -> Followers: Proposal
Followers -> Leader: ACK
Leader -> Followers: COMMIT

十四、Raft 与 ZAB 的区别

Raft 和 ZAB 都使用 Leader 和多数派,但关注点略有不同。

对比项 Raft ZAB
典型系统 etcd、Consul ZooKeeper
核心模型 复制日志 原子广播
Leader 选举 Raft 自身定义 ZooKeeper 选举机制
写入路径 Leader 复制日志 Leader 广播事务
工程目标 易理解、易实现 服务 ZooKeeper 数据模型
一致性基础 多数派 多数派

十五、Gossip:最终一致性的传播协议

Gossip 不是强一致性共识算法,而是一种最终一致性传播协议。

它的思想类似流言传播。

一个节点知道某个消息后,会随机告诉其他节点。被通知的节点再继续传播。

text 复制代码
A -> B, C
B -> D
C -> E
D -> F

经过多轮传播后,整个集群最终都会知道这个消息。

Gossip 的优点

  • 去中心化
  • 可扩展性强
  • 容错性好
  • 适合大规模集群状态传播

Gossip 的缺点

  • 不保证强一致
  • 收敛有延迟
  • 短时间内不同节点状态可能不同

典型应用

  • Cassandra 节点状态传播
  • Consul 成员发现
  • Dynamo 风格系统
  • 分布式缓存节点状态同步

十六、常见算法对比

算法 类型 一致性 是否依赖 Leader 是否阻塞 典型场景
2PC 分布式事务协议 强一致事务结果 协调者 会阻塞 XA 事务
3PC 分布式事务协议 尽量强一致 协调者 降低阻塞 理论方案较多
Paxos 共识算法 强一致 不强制固定 Leader 不依赖单点 理论共识
Multi-Paxos 日志共识 强一致 通常有 Leader 多数派可用即可 分布式存储
Raft 日志共识 强一致 多数派可用即可 etcd、Consul
ZAB 原子广播 强一致 多数派可用即可 ZooKeeper
Gossip 传播协议 最终一致 不阻塞 状态传播

十七、如何选择一致性算法

1. 如果你要做分布式事务

可以考虑:

  • 本地消息表
  • Saga
  • TCC
  • 2PC / XA

但在高并发互联网系统中,强 XA 事务通常不是首选,因为它会带来资源锁定、性能下降和可用性问题。

更常见的做法是业务补偿加最终一致性。

2. 如果你要做配置中心或注册中心

可以考虑:

  • Raft
  • ZAB
  • Multi-Paxos

这类系统通常要求元数据强一致,因为配置错误或服务发现错误会影响整个系统。

3. 如果你要做大规模状态传播

可以考虑 Gossip。

例如节点上下线、心跳状态、缓存拓扑变化等场景,不一定需要所有节点立即强一致。

4. 如果你要做分布式锁

应该优先选择已经成熟的 CP 系统,例如:

  • ZooKeeper
  • etcd

分布式锁对一致性要求很高,不建议基于普通缓存系统随意实现。


十八、工程实践中的取舍

真实系统很少只追求单一指标。

一致性越强,通常意味着:

  • 写入延迟更高
  • 可用性更容易受网络影响
  • 系统实现更复杂
  • 运维成本更高

一致性越弱,通常意味着:

  • 性能更好
  • 可用性更高
  • 业务需要处理冲突
  • 需要补偿、重试、幂等和对账机制

所以工程上真正重要的问题不是"哪个算法最好",而是:

text 复制代码
这个业务到底需要多强的一致性?
数据短暂不一致会造成什么后果?
是否可以通过补偿机制修复?
用户是否能感知?
资金、库存、权限、配置等关键数据是否允许最终一致?

十九、一个简单的选择建议

业务场景 推荐一致性策略
金融转账 强一致或可靠最终一致,必须有对账
库存扣减 强约束库存可用 CP,普通库存可最终一致
用户资料更新 最终一致通常可接受
配置中心 强一致
注册中心 CP 或 AP 取决于业务容忍度
分布式锁 强一致
日志采集 最终一致
缓存同步 最终一致
订单状态流转 本地事务 + 消息最终一致 + 幂等

二十、总结

分布式一致性算法本质上是在不可靠环境中协调多个节点的决策。

2PC 和 3PC 主要面向分布式事务提交,强调多个参与者对事务结果达成一致。

Paxos、Multi-Paxos、Raft 和 ZAB 属于共识或日志复制协议,强调多个节点对操作顺序和状态变更达成一致。

Gossip 则不追求强一致,而是通过传播机制实现最终一致,适合大规模状态同步。

在工程实践中,一致性不是越强越好。强一致能减少业务复杂度,但会牺牲性能和可用性;最终一致性能提升系统吞吐和容错能力,但要求业务具备幂等、重试、补偿和对账能力。

设计分布式系统时,最重要的是先判断业务的一致性边界,再选择合适的算法和架构,而不是盲目追求某个"最强"的一致性方案。

相关推荐
luj_17686 小时前
塔防牌:策略与卡牌的智慧碰撞
服务器·c语言·开发语言·经验分享·算法
郝学胜-神的一滴6 小时前
干货版《算法导论》17:二叉树核心原理、遍历逻辑与高阶实操全解
数据结构·c++·python·算法·计算机·编程
爱编程的小新☆6 小时前
【LeetCode】从递归到 Flood Fill:5 道题吃透 DFS 的选择、回溯与标记
java·算法·leetcode·深度优先·回溯·flood fill
Water_Sunzhipeng6 小时前
2024牛客暑期多校训练营1
算法
hetao17338377 小时前
2026-08-09~08-14 hetao1733837 的刷题记录
c++·算法
技术小黑7 小时前
RNN算法实战系列06 | LSTM 实现糖尿病探索与预测
rnn·算法·lstm
疯狂打码的少年7 小时前
【数据结构】二叉树的性质(五大性质+计算)
数据结构·笔记·算法
wabs6667 小时前
关于图论【A*算法 | 卡码网127.骑士的攻击的思考】
数据结构·算法·图论·卡码网·广搜的改进版
CIO_Alliance8 小时前
AI认知系列(3)| 数据、算法、算力、场景四要素协同
人工智能·算法·ipaas·系统集成·企业cio联盟·企业级ai化转型
汽车仪器仪表相关领域8 小时前
KRYPTON坚固型IP67 EtherCAT总线数据采集模块:工业级分布式采集方案
分布式·功能测试·汽车·压力测试·可用性测试