ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

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

2026/8/13 13:00:45 拓冰建站 浏览量
分布式一致性算法详解:从 2PC、3PC 到 Paxos、Raft、ZAB

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

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


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

典型场景包括:

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

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

A: balance = 100 B: balance = 100 C: balance = 100

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

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


二、一致性的不同层次

1. 强一致性

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

例如:

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

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

2. 最终一致性

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

例如:

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

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

Coordinator -> Participant A: Can commit? Coordinator -> Participant B: Can commit? Coordinator -> Participant C: Can commit?

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

YES / NO

阶段二:Commit / Rollback

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

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

所有人 YES -> COMMIT 任意人 NO -> ROLLBACK

2PC 的优点

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

2PC 的缺点

2PC 最大的问题是阻塞。

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

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

Participant A: 已 prepared,但不知道最终结果 Participant B: 已 prepared,但不知道最终结果 Coordinator: 宕机

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


五、3PC:三阶段提交

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

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

  1. CanCommit
  2. PreCommit
  3. DoCommit

3PC 的核心思路

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

流程大致如下:

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 个。

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

多数派 1: A B C 多数派 2: C D E 交集: C

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

Paxos 两个阶段

第一阶段:Prepare / Promise

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

Prepare(n)

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

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

这叫 Promise。

第二阶段:Accept / Accepted

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

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

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

Accept(n, value)

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

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

Paxos 的优点

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

Paxos 的缺点

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

七、Multi-Paxos

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

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

log[1] = set x = 1 log[2] = set y = 2 log[3] = delete z

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

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

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

Multi-Paxos 的核心优化

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

Prepare -> Promise Accept -> Accepted

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

Accept -> Accepted

这让它更适合工程系统。


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

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

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

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

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

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

九、Raft 的角色

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

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

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

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,降低选票冲突概率。

Node A timeout: 150ms Node B timeout: 230ms Node C timeout: 310ms

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


十一、Raft 日志复制

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

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

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 也提交。

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

十二、Raft 的安全性

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

1. Leader 只追加日志

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

2. 日志匹配原则

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

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. 各节点应用事务
Client -> Leader Leader -> Followers: Proposal Followers -> Leader: ACK Leader -> Followers: COMMIT

十四、Raft 与 ZAB 的区别

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

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

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

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

它的思想类似流言传播。

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

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

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


十八、工程实践中的取舍

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

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

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

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

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

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

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

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

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

二十、总结

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

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

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

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

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

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