← [ BACK_TO_NOTES ]

分布式事务

解释一个业务动作跨数据库、服务或消息系统后,为何单库 ACID 不再覆盖全部副作用,并对比 2PC、Saga、Transactional Outbox 与幂等补偿的适用边界。

#synthesis #growing #backend #architecture

[!info] related notes

分布式事务

[!abstract] 核心结论 分布式事务处理一个业务操作跨越多个独立事实源时的一致性。工程上先区分是否真的需要“所有参与者原子提交”,还是允许通过 Saga、Outbox、幂等和补偿达到可观察的最终一致。

问题从哪里出现

Order DB commit succeeds
→ Inventory call succeeds
→ Payment call times out
→ Notification not sent

单个本地数据库事务无法覆盖其他数据库、Broker 和第三方 API。失败时系统需要知道哪些步骤已提交、哪些结果未知、怎样继续或补偿。

先定义业务不变量

不要先问“用 2PC 还是 Saga”,先问:

  • 哪些状态必须同时成立?
  • 哪些步骤可延迟?
  • 哪些副作用可补偿?
  • 哪些外部系统支持幂等和查询状态?
  • 用户能否看到 Pending / Processing?
  • 最长不一致窗口是多少?

很多需求可以通过重新划分 Aggregate / 服务边界,回到一个本地事务中解决。

Two-Phase Commit(2PC)

Phase 1: Prepare
Coordinator asks all participants to prepare

Phase 2: Commit / Abort
If all prepared → commit
Else → abort

优点:接近跨资源原子提交。

代价:

  • Coordinator 与 Participant 状态复杂;
  • Prepared Resource 可能长期占锁;
  • 故障恢复和 Heuristic Outcome 困难;
  • 延迟与可用性受最慢参与者影响;
  • 外部 HTTP API 通常不支持 XA / Prepare。

适合参与者可控、强原子性确有必要且规模有限的场景。

Saga

Saga 将长事务拆成一系列本地事务,每步成功后发布下一步;失败时执行补偿:

Create Order
→ Reserve Inventory
→ Authorize Payment
→ Confirm Order

failure at payment
→ Release Inventory
→ Cancel Order

补偿不是数据库 Rollback:已经发出的邮件、外部扣款或用户观察可能无法完全撤销。Saga 需要显式状态机、幂等、重试、超时和人工介入。

Choreography 与 Orchestration

  • Choreography:服务通过事件自行响应,耦合分散但整体流程难观察;
  • Orchestration:中央协调器发命令并记录状态,流程清晰但协调器成为关键组件。

Transactional Outbox

解决“本地数据库提交 + 发布消息”的双写:

single DB transaction:
  update business tables
  insert outbox event
commit

publisher / CDC
→ read outbox
→ publish to broker
→ mark / checkpoint

Outbox 让业务状态和“待发布事实”同事务提交,但仍可能重复发布,因此 Consumer 必须幂等。

Inbox / Processed Message

Consumer 在自己的本地事务里:

insert message_id unique
+ update business state
commit

重复投递时唯一约束阻止重复副作用。Inbox 与 Outbox 组合常用于最终一致集成。

TCC / Reservation

Try–Confirm–Cancel 先预留资源,再确认或取消:

Try: reserve inventory / funds
Confirm: finalize
Cancel: release reservation

它要求参与者专门实现三套业务接口和超时清理,适合资源预留语义明确的高价值流程。

Unknown Outcome

外部调用 Timeout 时不能直接假设失败:

payment request sent
→ provider charges successfully
→ response lost

需要稳定 Idempotency Key、查询接口和 Reconciliation。生成新 Key 再重试可能重复扣款。

最终一致不等于无限等待

应定义:

  • SLA / Maximum Convergence Time;
  • Retry Budget;
  • Dead Letter / Manual Review;
  • User-visible Pending State;
  • Reconciliation Job;
  • Compensation Failure Handling。

没有收敛目标和修复路径的“最终一致”只是把错误拖延。

设计顺序

1. Define invariant and source of truth
2. Reduce cross-boundary writes if possible
3. Choose local transaction boundaries
4. Add idempotency and status query
5. Choose 2PC / Saga / TCC / Outbox
6. Persist workflow state and attempts
7. Add timeout, retry, compensation, reconciliation
8. Observe business completion, not just message ACK

设计检查表

  • 每一步的本地提交点和 Source of Truth 明确。
  • Unknown Outcome 有查询和 Reconciliation。
  • Command / Message 使用稳定 Idempotency Key。
  • Compensation 的业务含义与失败处理明确。
  • Outbox Publisher 和 Consumer 都允许重复。
  • Pending / Failed / Manual Review 状态对用户可解释。
  • Trace 能还原完整 Saga / Transaction Timeline。
  • 选择 2PC 前已证明强原子性和参与者能力确实需要。
创建于 2026/9/4 更新于 2026/9/4
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本