Distributed Transactions
分布式事务的挑战
Distributed transaction 是跨两个或多个 databases 的一组数据操作。它通常在网络连接的多个 nodes 上协调执行,也可能发生在同一 server 上的多个 databases。
为什么需要 distributed transactions?
单库里的 ACID transaction 只影响一个 database;但 distributed transaction 需要在多个 databases 上改数据,所以协调 commit / rollback 更复杂。
换句话说:要么所有 nodes 都 commit,要么全部 abort 并整体 rollback。这就是 distributed transactions 存在的原因。
下面是一些常见方案。
Two-Phase Commit (2PC)

Two-Phase Commit 是一种分布式协议,用来协调所有参与节点决定 commit 还是 abort(rollback)。
它能在很多临时故障场景下继续工作,因此被广泛使用。但它无法覆盖所有故障组合,极少数情况下可能需要人工干预。
2PC 需要一个 coordinator node,负责在多个节点间协调 transaction。它分两阶段建立共识:
Phases
Prepare phase
Coordinator 向各 participant 收集是否“准备好”的共识。如果任一节点未准备好,transaction 会被 abort。
Commit phase
如果所有 participant 都返回 prepared,coordinator 就通知所有节点 commit。若此时发生失败,transaction 需要 rollback。
Problems
- 某个节点 crash 了怎么办?
- coordinator 自己 crash 了怎么办?
- 这是一个 blocking protocol。
Three-Phase Commit (3PC)

3PC 是 2PC 的扩展,把 commit 阶段拆成两步,用来缓解 2PC 的 blocking 问题。
Phases
Prepare phase
同 2PC。
Pre-commit phase
Coordinator 发出 pre-commit,所有 participant 必须确认。如果某个节点超时未收到,则 transaction abort。
Commit phase
与 2PC 的 commit 类似。
为什么 Pre-commit 有用?
- 如果 participant 处于 pre-commit,说明所有人都完成了 prepare。
- 每个 phase 都可以 timeout,避免无限等待。
Sagas

Saga 是一系列 local transactions。每个 local transaction 更新 database 并发布 message/event 触发下一个 local transaction。如果某个 local transaction 因业务规则失败,就执行一系列 compensating transactions 来撤销之前的改动。
Coordination
常见两种实现:
- Choreography:每个 local transaction 发布 domain events,触发其他服务的 local transactions。
- Orchestration:由 orchestrator 统一指挥各参与者执行本地事务。
Problems
- Saga pattern 很难 debug。
- 容易产生参与者之间的循环依赖。
- 缺乏 participant 的数据隔离会带来 durability 挑战。
- 测试困难,因为需要所有服务同时运行才能模拟 transaction。