4. 分布式事务解决方案概览

在金融系统中,一笔交易往往横跨账户、账务、清算、风控、通知等多个服务。单体时代的本地事务只能保证单个数据库的 ACID,一旦跨服务、跨库、跨中间件,就必须引入分布式事务方案。本节不深入某一种方案的实现细节,而是先建立一张“全景地图”:把七种主流方案放在同一坐标系里,理解它们各自解决什么问题、付出什么代价、适合什么场景,从而在架构选型时不再凭感觉拍板。

一、核心原理:一致性谱系与代价权衡

所有分布式事务方案,本质上都在回答同一个问题:当多个参与者的操作无法用一个本地事务原子提交时,如何让最终结果保持一致? 区别在于它们选择了一致性的“强度”和“时机”。

  • 强一致派:2PC、3PC 追求提交时刻的原子性,通过协调者统一裁决,代价是同步阻塞、协调者单点、性能下降。
  • 补偿派:TCC、Saga 放弃“同时成功”,改为“先做、失败再补”,用业务补偿换可用性与吞吐。
  • 消息派:Outbox、可靠消息、最大努力通知,把“跨服务调用”转化为“本地事务 + 消息投递”,用最终一致换解耦与弹性。

理解这条谱系后,选型就不再是“哪个方案最好”,而是“哪个方案的代价我能接受”。金融核心账务通常偏强一致,营销、积分、通知类场景则更适合最终一致。

一致性强度 ← 方案谱系 → 可用性与吞吐 强一致 最终一致 2PC / 3PC 同步阻塞·协调者 TCC Try-Confirm-Cancel Saga 长流程·补偿链 Outbox 本地表+投递 可靠消息 MQ 事务消息 最大努力通知 重试+对账兜底 代价:阻塞/复杂度/补偿成本/消息可靠性/人工兜底 越靠右,越依赖最终一致与对账

二、方法流程:七种方案的执行骨架

把七种方案拆成“执行骨架”,能快速看清它们的差异。下面用清单形式给出每种方案的关键步骤与核心风险点。

  1. 2PC:协调者询问所有参与者能否提交 → 参与者锁定资源并投票 → 协调者裁决提交或回滚。风险:同步阻塞、协调者宕机导致悬挂。
  2. 3PC:在 2PC 前增加 CanCommit 预询问,并引入超时机制,降低阻塞范围,但仍无法彻底解决网络分区下的一致性问题。
  3. TCC:Try 预留资源 → Confirm 确认扣减 → Cancel 释放预留。要求每个业务操作都实现三个接口,且需处理空回滚、幂等、悬挂。
  4. Saga:把长事务拆成多个本地事务 T1…Tn,每个 Ti 配一个补偿 Ci;正向失败时反向执行 C(i-1)…C1。适合流程长、参与者多的业务。
  5. Outbox:业务数据与事件写入同一本地事务的 outbox 表 → 投递器轮询或 CDC 捕获 → 发送到 MQ → 下游消费。核心是“本地事务保证事件不丢”。
  6. 可靠消息:利用 MQ 的事务消息(如半消息 + 回查),保证“本地事务成功”与“消息可投递”一致。
  7. 最大努力通知:上游尽最大努力重试通知下游,下游做幂等;仍失败则依赖定时对账与人工干预。

关键判断:如果业务能接受“中间态可见”,优先选 Saga 或消息类方案;如果业务要求“要么全成功要么全不可见”,才考虑 TCC 或 2PC。金融账务中的“冻结/解冻”天然适合 TCC,而“积分发放”更适合可靠消息。

三、案例场景:一笔跨行转账的选型推演

假设用户从 A 银行账户转账到 B 银行账户,涉及本行扣款、跨行清算、对方入账、短信通知四个环节。不同环节对一致性的要求不同:

  • 扣款与入账:必须强一致或可补偿,否则会出现“钱扣了没到账”。可采用 TCC:Try 冻结付款方金额,Confirm 扣减并通知清算,Cancel 解冻。
  • 清算与对账:跨行清算通常异步,适合 Saga 或可靠消息,配合日终对账兜底。
  • 短信通知:允许丢失或延迟,采用最大努力通知即可,失败不影响主交易。

如果强行用 2PC 把短信通知也纳入事务,会导致主交易被通知服务拖慢甚至阻塞,这是典型的“用错方案”。选型的本质是按业务容忍度分层,而不是一刀切。

四、误区与复盘:选型中最容易踩的坑

误区一:认为 TCC 一定比 Saga 强。 TCC 的 Confirm/Cancel 需要业务实现,开发成本高;Saga 虽然补偿逻辑复杂,但对已有服务侵入更小。没有银弹,只有匹配。

误区二:把 Outbox 当成“万能消息队列”。 Outbox 解决的是“本地事务与消息发送的原子性”,不解决消息重复消费、顺序消费,这些仍需下游幂等与去重。

误区三:忽略空回滚与悬挂。 TCC 中 Cancel 先于 Try 到达、或 Try 超时后 Confirm 才到,都会导致数据错乱。必须用事务控制表记录状态,并做幂等校验。

复盘时建议用一张对照表来固化选型结论,避免每次讨论都从头争论。下表可作为团队选型清单:

方案 一致性 侵入性 性能 典型场景 主要风险
2PC 强一致 低(依赖数据库) 差 同构数据库、短事务 阻塞、协调者单点
3PC 强一致(分区下弱) 低 较差 对阻塞敏感的场景 网络分区仍可能不一致
TCC 最终一致(可强) 高 好 资金冻结、库存预留 空回滚、悬挂、幂等
Saga 最终一致 中 好 长流程、多参与者 补偿逻辑复杂、无隔离
Outbox 最终一致 中 好 事件驱动、数据同步 投递延迟、重复消费
可靠消息 最终一致 中 好 异步解耦、通知 MQ 可用性依赖
最大努力通知 弱一致 低 最好 短信、推送、日志 可能丢失,需对账

选型口诀:强一致看 2PC/3PC,资金类看 TCC,长流程看 Saga,解耦看 Outbox/可靠消息,通知类看最大努力通知。先定一致性底线,再定侵入性与成本,最后用对账兜底。