3、常见分布式事务方案:TCC模式、Saga模式、可靠消息最终一致性、最大努力通知
在微服务与分布式系统架构中,单一数据库的本地事务(ACID)无法跨服务边界生效。为解决跨服务、跨数据库的数据一致性问题,业界演化出四种主流分布式事务方案。本章从原理、适用场景、优缺点三个维度进行对比分析,并给出开发环境下的选型建议。
3.1 方案总览与对比矩阵
四种方案在一致性强度、侵入性、吞吐量、回滚能力上各有侧重。下表从关键维度进行横向对比:
| 方案 | 一致性类型 | 业务侵入性 | 吞吐量 | 回滚能力 | 典型场景 |
|---|---|---|---|---|---|
| TCC | 强一致性(最终一致) | 高(需实现三阶段接口) | 中等 | 支持(Cancel阶段) | 短事务、高一致性要求 |
| Saga | 最终一致性 | 中(需实现补偿逻辑) | 高 | 支持(补偿事务) | 长事务、跨多服务编排 |
| 可靠消息最终一致性 | 最终一致性 | 低(依赖消息中间件) | 高 | 不支持(需业务补偿) | 异步解耦、削峰填谷 |
| 最大努力通知 | 最终一致性(弱) | 低(回调/轮询) | 极高 | 不支持 | 非核心业务、通知类 |
开发环境选型提示: 在 development 环境做单元测试时,优先选择可靠消息最终一致性方案进行 Mock 测试,因其对业务代码侵入最小,便于使用嵌入式消息中间件(如 H2 + ActiveMQ/Artemis)模拟异步场景。
3.2 TCC模式(Try-Confirm-Cancel)
TCC 是一种补偿型事务方案,将整个分布式事务拆分为三个阶段:Try(预留资源)、Confirm(确认执行)、Cancel(回滚释放)。每个参与者服务都需要实现这三个接口。
- Try 阶段: 尝试执行业务,完成资源检查和预留。例如:冻结库存、预扣余额。
- Confirm 阶段: 如果所有参与者 Try 成功,则全局事务管理器调用 Confirm 接口,真正执行业务操作。
- Cancel 阶段: 如果任一参与者 Try 失败或超时,则调用所有已成功 Try 的参与者的 Cancel 接口,释放预留资源。
核心特点: TCC 是业务层面的两阶段提交,不依赖数据库 XA 协议,性能优于传统 XA。但要求业务方提供三组幂等接口,开发成本较高。
3.3 Saga模式
Saga 模式将一个长事务拆分为一组有序的子事务(本地事务),每个子事务都对应一个补偿事务。当某个子事务失败时,Saga 协调器反向调用已成功子事务的补偿操作。
- 编排方式: 分为事件编排(Choreography)和命令编排(Orchestration)两种。前者通过事件驱动,后者由中央协调器控制。
- 补偿设计: 补偿事务必须是幂等的,且能正确处理部分成功场景。
- 适用场景: 跨多个微服务的业务流程,如订单创建 → 支付 → 库存扣减 → 物流发货。
注意: Saga 模式不提供隔离性(Isolation),开发环境测试时需关注脏读和幻读问题。建议在单元测试中通过 Mock 补偿逻辑来验证回滚路径。
3.4 可靠消息最终一致性
该方案通过消息中间件(如 RocketMQ、Kafka)实现事务消息,保证本地事务与消息发送的原子性。核心流程如下:
- 发送半消息: 生产者向 MQ 发送一条“半消息”(暂不可消费)。
- 执行本地事务: 生产者执行本地数据库操作。
- 提交/回滚消息: 本地事务成功则提交消息(消费者可见);失败则回滚消息。
- 消息补偿: MQ 定期回查未决消息,确保最终一致性。
3.5 最大努力通知
最大努力通知是最弱的一致性方案,适用于对实时性要求不高、允许短暂不一致的场景。核心思想是:发起方尽最大努力将结果通知给接收方,不保证 100% 送达。
- 实现方式:
- 回调通知: 发起方主动调用接收方提供的回调接口。
- 轮询查询: 接收方定期主动查询发起方的状态。
- 重试机制: 通常配合指数退避重试,达到最大次数后放弃或转入人工处理。
- 典型场景: 支付结果通知、短信发送状态、第三方平台回调。
开发环境测试要点: 在单元测试中,最大努力通知通常通过 Mock 回调接口并验证重试次数来实现。建议使用
RetryTemplate(Spring Retry)模拟重试逻辑,并断言最终调用次数符合预期。
3.6 方案选型建议
在 development 环境进行单元测试与鉴权拦截测试时,建议遵循以下选型原则:
| 业务场景 | 推荐方案 | 单元测试关注点 |
|---|---|---|
| 资金类、库存类(强一致) | TCC | Try/Confirm/Cancel 三阶段幂等性、超时处理 |
| 长流程编排(订单→支付→物流) | Saga | 补偿事务正确性、状态机转换 |
| 异步解耦、削峰填谷 | 可靠消息最终一致性 | 半消息状态、本地事务回滚、消息重投 |
| 非核心通知、第三方回调 | 最大努力通知 | 重试次数、回调超时、降级逻辑 |
鉴权拦截测试提示: 在 development 环境测试分布式事务时,鉴权拦截器(如 Token 校验、权限校验)应优先于事务管理器执行。建议在单元测试中通过
@WithMockUser 或自定义 SecurityContext 来模拟已认证用户,避免鉴权逻辑干扰事务流程的验证。