3. 常见分布式事务方案:TCC模式、Saga模式、本地消息表、可靠消息最终一致性

在分布式系统中,传统数据库的 ACID 事务无法跨服务边界生效。本章聚焦四种主流分布式事务方案,从原理、适用场景到压测安全权限设计的关注点进行对比分析。理解这些方案的差异,是后续构建压测场景库与权限模型的基础。

3.1 方案总览与对比

四种方案在一致性保证、侵入性、性能与回滚能力上各有侧重。下表从核心维度进行横向对比:

方案 一致性模型 业务侵入性 回滚能力 典型延迟 压测关注点
TCC 模式 强一致性(最终一致) 高(需实现 Try/Confirm/Cancel) 强(Cancel 阶段显式回滚) 低(2次 RPC) 幂等性、空回滚、悬挂
Saga 模式 最终一致性 中(需实现正向/补偿事务) 强(补偿事务回滚) 中(异步编排) 补偿幂等、状态机并发
本地消息表 最终一致性 低(依赖本地事务+定时任务) 弱(需手动补偿) 高(轮询间隔) 消息积压、重复投递
可靠消息最终一致性 最终一致性 中(依赖消息中间件) 中(消息重试+死信) 中(异步消息) 消息顺序、事务状态表
压测安全提示: 在集成测试压测场景中,TCC 的 Cancel 与 Saga 的补偿事务是权限校验的高危区——回滚操作若未做鉴权,攻击者可利用回滚接口破坏数据一致性。

3.2 TCC 模式(Try-Confirm-Cancel)

TCC 将分布式事务拆分为三个阶段,每个参与者服务都需要实现对应的接口。其核心思想是“预留资源 → 确认使用 → 取消预留”。

  • Try 阶段: 尝试执行业务,完成资源预留或检查。例如,冻结库存、预扣余额。
  • Confirm 阶段: 如果所有参与者 Try 成功,则全局协调器调用 Confirm 完成实际业务操作。
  • Cancel 阶段: 如果任一参与者 Try 失败或超时,则调用 Cancel 释放预留资源。

以下 SVG 展示了 TCC 三阶段的典型调用流程:

TCC 三阶段调用流程 TCC 模式三阶段调用流程 全局事务协调器 服务A (Try) 服务B (Try) 服务C (Try) 服务A (Confirm) 服务B (Confirm) 服务C (Confirm) 服务A (Cancel) 服务B (Cancel) 服务C (Cancel) 说明:实线为正常 Try→Confirm 路径;红色虚线为异常时 Cancel 回滚路径
压测场景库设计要点:
  • 幂等性压测: 对 Confirm 和 Cancel 接口重复调用,验证幂等锁是否生效。
  • 空回滚压测: 模拟 Try 未执行但 Cancel 被调用的情况,验证服务不报错。
  • 悬挂压测: 模拟 Cancel 先于 Try 到达,验证资源状态机正确处理。

3.3 Saga 模式

Saga 模式通过将一个长事务拆分为多个本地事务,每个本地事务对应一个补偿事务。当某个本地事务失败时,按逆序调用补偿事务进行回滚。Saga 分为两种编排方式:

  • Choreography( choreography): 每个服务在完成本地事务后,发布事件触发下一个服务。无中心协调器。
  • Orchestration(编排): 由一个协调器(Orchestrator)负责通知各服务执行正向或补偿操作。

以下 SVG 展示了基于编排的 Saga 执行流程:

Saga 编排模式执行流程 Saga 编排模式(Orchestration)执行流程 Saga 编排器 T1: 创建订单 T2: 扣减库存 T3: 扣减余额 C3: 恢复余额 C2: 恢复库存 C1: 取消订单 说明:正向执行 T1→T2→T3;若 T3 失败,编排器触发逆序补偿 C3→C2→C1 压测关注:补偿事务的幂等性、编排器状态机在高并发下的正确性
安全权限设计警告: Saga 的补偿事务接口必须与正向事务接口具有同等级别的权限校验。压测中常见的安全漏洞是补偿接口未做鉴权,导致攻击者可以绕过正向流程直接调用补偿,造成数据错乱。

3.4 本地消息表

本地消息表方案将分布式事务拆解为“本地事务 + 消息表 + 定时任务”。核心思路是:业务操作与消息写入在同一个本地事务中完成,然后通过定时任务轮询消息表,将消息投递给下游服务。

  • 优点: 不依赖消息中间件的事务特性,实现简单,适合中小规模系统。
  • 缺点: 消息表与业务库耦合,定时轮询存在延迟,且需要处理消息重复投递。
压测场景库设计要点:
  • 消息积压压测: 模拟下游服务处理缓慢,观察消息表行数增长与定时任务消费能力。
  • 重复投递压测: 模拟定时任务重复扫描,验证下游服务的幂等性。
  • 数据库锁竞争压测: 高并发下消息表行锁与业务表行锁的相互影响。

3.5 可靠消息最终一致性

该方案通过消息中间件(如 RocketMQ、Kafka)的事务消息或半消息机制,保证本地事务与消息发送的原子性。典型流程如下:

  1. 生产者发送半消息(prepare)到 MQ,MQ 返回消息 ID。
  2. 生产者执行本地事务。
  3. 根据本地事务结果,提交(commit)或回滚(rollback)半消息。
  4. MQ 投递已提交的消息给消费者;若超时未确认,MQ 主动回查生产者事务状态。

下表对比了本地消息表与可靠消息最终一致性方案的关键差异:

对比维度 本地消息表 可靠消息最终一致性
消息存储 业务数据库的消息表 消息中间件内部存储
事务保证 依赖本地数据库事务 依赖 MQ 事务消息/半消息机制
延迟 高(定时轮询间隔) 低(异步实时投递)
扩展性 差(消息表与业务库耦合) 好(MQ 可水平扩展)
压测重点 数据库连接池、轮询 SQL 性能 MQ 吞吐、回查接口性能
压测安全提示: 可靠消息方案中,MQ 的回查接口(check callback)是安全权限设计的薄弱环节。压测时需验证回查接口是否做了身份校验,防止攻击者伪造回查请求导致事务状态错误。

3.6 方案选型与压测策略总结

在集成测试压测场景库建设中,方案选型直接影响压测脚本的设计粒度:

  • TCC: 适合对一致性要求高、业务资源可预扣的场景(如库存、账户)。压测需重点覆盖 Cancel 路径的并发与幂等。
  • Saga: 适合长流程、异步化场景(如订单履约、旅游预订)。压测需关注编排器状态机在高并发下的正确性。
  • 本地消息表: 适合中小团队、对延迟不敏感的场景。压测需关注消息表与业务表的锁竞争。
  • 可靠消息最终一致性: 适合高吞吐、对一致性要求中等的场景。压测需关注 MQ 集群的吞吐与回查接口的性能。