分布式事务
单库事务依赖数据库的 ACID 能力;跨服务或跨数据源后,没有天然的全局原子提交。方案选择应围绕一致性要求、可用性、吞吐量和业务补偿成本,而不是追求统一解法。
2PC / XA
2PC 由协调者驱动:第一阶段询问参与者是否可以提交,第二阶段统一提交或回滚。XA 是数据库与事务管理器之间常用的两阶段提交规范。
它能提供较强的一致性,但参与者在事务完成前可能持有锁或连接资源。同步等待、协调者可用性和故障恢复都会拉低吞吐量,因此更适合事务短、强一致性要求高且参与者支持 XA 的场景。
TCC
TCC 是业务层的两阶段提交。每个参与者(RM)都需要实现三个操作:
- Try:校验条件并预留资源;
- Confirm:确认并完成业务动作;
- Cancel:撤销预留资源。
事务协调器(TC)协调参与者:所有 Try 成功后执行 Confirm;任一 Try 失败或超时则执行 Cancel。Try 成功意味着参与者必须能够最终完成 Confirm,因此 Confirm 与 Cancel 都必须可重试且幂等。
TCC 以业务预留替代长时间的数据库行锁,通常有更好的并发能力;代价是实现侵入性高。还必须处理空回滚和悬挂:Cancel 可能先于 Try 到达,迟到的 Try 不能再次预留资源。实践中应通过本地事务记录每个分支的状态,并据此拒绝非法状态转换。
Saga
Saga 将一个长流程拆为多个本地事务,每一步都定义对应的补偿动作。前序步骤成功、后续步骤失败时,按逆序执行补偿。
它适合跨服务、流程长且可接受最终一致性的业务。补偿是新的业务操作,不等同于数据库回滚;设计时必须明确哪些状态可补偿,以及补偿失败后的人工或自动处置方式。
事务消息
事务消息解决的是“本地状态变更”和“发布消息”不能原子完成的问题,核心目标是可靠投递,而非让多个服务同步回滚。
Outbox 模式
在同一个本地数据库事务中,同时写入业务数据和 outbox 消息记录。后台投递器读取 outbox 并发送到 MQ,投递成功后更新记录状态。
这保证本地提交成功的事件最终至少投递一次。因此消费者必须幂等,系统也必须接受短暂的不一致;下游处理失败时,应通过重试、补偿或对账恢复,而不是回滚上游已提交的本地事务。
RocketMQ 事务消息
RocketMQ 以半消息和状态回查实现类似的可靠性:
- Producer 先发送对消费者不可见的半消息;
- Producer 执行本地事务;
- 本地事务成功则提交消息,失败则回滚消息;
- 若 Producer 未完成确认,Broker 回查本地事务状态后决定提交或回滚。
本地事务的结果必须可查询,并且消费者仍需按至少一次投递来设计。
方案取舍
| 方案 | 一致性 | 主要代价 | 适用边界 |
|---|---|---|---|
| 2PC / XA | 强一致性 | 阻塞与资源占用 | 短事务、数据库支持 XA |
| TCC | 业务强一致性 | 三套业务逻辑与状态治理 | 资源可预留、需要较高并发 |
| Saga | 最终一致性 | 补偿设计复杂 | 长流程、跨服务编排 |
| 事务消息 | 最终一致性 | 幂等、重试与对账 | 异步驱动的状态传播 |