Skip to content

分布式事务

2PC/3PC、TCC、Saga、本地消息表、Seata 选型。

Updated View as Markdown
For humans

分布式事务

校招考察频度:☆ 中频(重点常考·大厂分水岭)

微服务和分库分表之后,一个业务操作要跨多个数据库或服务,本地事务失效,需要分布式事务方案。主线:强一致方案(2PC/TCC)和最终一致方案(Saga/本地消息表),选型看一致性要求和吞吐。

强一致:2PC 与 3PC

2PC(两阶段提交):协调者先问所有参与者”能提交吗”(准备阶段),全部同意才广播提交,任一拒绝则全部回滚。

问题:准备阶段后协调者宕机,参与者阻塞等待;协调者单点故障;同步阻塞性能差。

3PC:在 2PC 基础上加超时机制和 CanCommit 阶段,减少阻塞窗口,但引入新问题(网络分区时可能违反一致性),实际应用少。

2PC 在分布式事务里更多作为理论基础:XA 协议就是 2PC 的数据库实现,性能开销大,高并发场景基本不用。

TCC:业务补偿

TCC(Try-Confirm-Cancel)把每个操作拆成三个方法:

  • Try:预留资源(冻结库存、冻结金额)
  • Confirm:确认执行(扣减冻结的库存)
  • Cancel:取消回滚(释放冻结)

优势:不依赖数据库锁,性能比 2PC 好。代价:业务侵入大,每个操作要写三个方法;要处理幂等、空回滚(Try 没执行就收到 Cancel)、悬挂(Cancel 先于 Try)。Seata 的 TCC 模式是生产常用选择。

Saga:最终一致

Saga 把长事务拆成一系列本地事务,每个事务有对应的补偿事务。正向执行,失败则反向补偿。两种编排:编排式(一个协调者串流程)和协同式(事件驱动,各服务自己订阅和响应)。

优势:无锁、适合长流程。代价:没有隔离性(中间状态对外可见),补偿逻辑要自己写,业务要能容忍中间状态。

本地消息表(可靠消息最终一致)

写业务和写消息表在同一个本地事务里,消息表作为”发出去的保证”:

  1. 业务操作和消息写入同事务提交
  2. 定时任务扫描未发送消息,投递 MQ
  3. 消费方处理成功后回执,标记消息已处理

变体是事务性发件箱(Transactional Outbox)模式(用 PostgreSQL WAL 逻辑复制 / CDC 监听替代定时扫描发信)。这是最终一致方案里实现最简单、最可靠的,适合异步解耦场景。

选型

方案一致性性能业务侵入适用
XA(2PC)强低低低并发、强一致
TCC强中高核心资金类,Seata 支持
Saga最终高中长流程、跨服务
本地消息表最终高低异步、可延迟

一个务实的结论:大多数业务能接受最终一致,优先本地消息表或 Saga;只有资金类强一致场景才上 TCC。Seata 是目前最主流的分布式事务框架,支持 AT(自动补偿)、TCC、Saga 多种模式。

面试追问

  1. 2PC 的问题? 同步阻塞、协调者单点、准备后宕机参与者悬挂。是理论基础,XA 实现性能差
  2. TCC 和 2PC 的区别? TCC 用业务补偿替代数据库锁,Try 预留、Confirm 确认、Cancel 回滚。性能好但侵入大,要处理幂等、空回滚、悬挂
  3. Saga 怎么保证一致性? 正向本地事务加反向补偿事务,失败反向执行。没有隔离性,中间状态可见
  4. 本地消息表与 Outbox 模式原理? 业务和消息写在同事务,保证消息必定记录。Outbox 模式通过 CDC 监听数据库 WAL 逻辑变更实时推向 MQ,性能比定时轮询扫表更好
  5. Seata 怎么选模式? AT 模式自动补偿侵入最小,TCC 适合强一致核心链路,Saga 适合长流程。能接受最终一致就别上强一致
Navigation

Type to search…

↑↓ navigate↵ selectEsc close