柔性事务:Saga、TCC 与事务性发件箱
本文基于模型知识整理(生成时未联网核对),关键结论建议对照经典文献复核。
一句话定义
柔性事务放弃跨服务的强原子性,改用"本地事务 + 补偿/确认"把长流程拆成一串可回滚的本地事务:Saga 用逆序补偿、TCC 用预留-确认-取消、事务性发件箱用同事务写消息解决"改库与发消息不一致",共同换取高可用与低锁成本。
为什么重要
微服务架构下每个服务各有数据库,XA(kp-023)因阻塞与吞吐问题普遍被弃用;柔性事务是跨服务一致性的主流答案。但它的"最终一致"不是免费的:补偿要自己写、隔离性要自己管(脏读/丢失更新风险)、幂等与去重要自己兜底(kp-029)。
前置知识
kp-023(2PC 为何不适用)、kp-008(消息队列语义)。
核心概念
- Saga:长事务 T = T1…Tn,每个 Ti 配补偿 Ci;失败时逆序执行 C(n-1)…Ci+1 回滚已完成部分。两种协调方式:
- 编排式(choreography):服务间靠事件驱动,各自订阅触发下一步——松耦合,但流程分散难追踪; - 协同式(orchestration):中央协调器(状态机)驱动步骤——流程集中可视,但协调器是单点逻辑(不是单点数据)。
- TCC(Try-Confirm/Cancel):Try 预留资源(冻结金额、预占库存),Confirm 确认扣减,Cancel 释放预留。把"锁资源"显式业务化,隔离性更好,但每个参与方要写三个接口,且必须幂等、允许空回滚(Cancel 先于 Try 到达)。
- 事务性发件箱(transactional outbox):业务数据与"待发消息"在同一本地事务中写入 outbox 表,后台轮询/CDC 把消息投递到 MQ——解决"库改了消息没发 / 消息发了库没改"的双写不一致。
- BASE:基本可用(Basically Available)、软状态(Soft state)、最终一致(Eventual consistency)——柔性事务的总纲。
原理与机制
Saga 的隔离性缺口:Saga 中间态对外可见(T1 提交、T2 未执行),其他事务可能读到"半成品"(脏读)或在其上并发修改导致补偿后矛盾(丢失更新)。对策:语义锁(业务状态字段标记"处理中")、交换律补偿设计、或对关键步骤用 TCC 预留隔离。
补偿 ≠ 回滚:数据库回滚是"从没发生过";Saga 补偿是"发生过再撤销"(退款、解冻、释放库存)。因此补偿必须幂等、可重试、可空跑(补偿时业务可能已自己回滚),且不可补偿的步骤(发短信)只能放在最后或接受副作用。
发件箱 + 幂等消费组合:outbox 保证"不丢",消费端幂等(去重表/唯一键)保证"不重"——两个模式拼起来才是完整的至少一次正确链路(与 kp-008 投递语义、kp-029 幂等工程闭环)。
图示
Saga(协同式):
订单服务 ──创建订单──► 事件 ──► 库存服务扣减 ──► 事件 ──► 支付服务扣款
✗ 扣款失败
◄──逆序补偿: 恢复库存 + 取消订单◄──
TCC:
Try: 冻结账户100元(可用余额-100, 冻结+100)
Confirm: 冻结-100, 已扣-100 / Cancel: 冻结-100(释放)
Outbox:
[本地事务] 业务表 + outbox(id,payload) 同事务提交 → 轮询投递MQ → 消费幂等
实例或案例
- 电商下单:订单(本地事务) → outbox 投递 → 库存/TCC 预占 → 支付;失败走取消链路。
- Seata(阿里开源):AT(自动补偿)/TCC/Saga/XA 四模式,是国内柔性事务落地最广的框架。
- 跨行转账:TCC 冻结-确认模式是银行系统标准打法;补偿入账为冲正交易。
常见误区
- 误区一:"柔性事务没有一致性问题"。它把原子性问题换成了补偿正确性 + 隔离性管理问题,复杂度没有消失只是换了形态。
- 误区二:"补偿逻辑可以后补"。补偿与正向逻辑同等重要,缺失补偿测试是柔性事务事故的头号来源。
- 误区三:"发件箱投完消息就删"。必须确认 MQ 成功接收(ACK)后才能标记,否则窗口内消息丢失;且 outbox 要有归档策略防表膨胀。
与其他知识点的关系
自测题
- Saga 与 2PC 的根本取舍?
答:2PC 阻塞持锁换强原子性;Saga 无全局锁、可用性高,但中间态可见(弱隔离)且需自写补偿,一致性为最终一致。
- TCC 的"空回滚"是什么问题?
答:Try 因网络延迟未到达,Cancel 先被执行;Cancel 必须能识别"无预留可释放"并幂等成功,否则悬挂或报错阻断流程。
- 事务性发件箱解决哪个双写问题?
答:业务落库与消息发送跨两个系统无法原子;把消息写进同库同事务,再异步投递,保证两者不脱节。
延伸阅读
- Hector Garcia-Molina & Salem, "Sagas"(SIGMOD 1987)。
- Chris Richardson《Microservices Patterns》(Saga/outbox 模式专著)。
- Chris Richardson, "PATTERN: Transactional outbox"(microservices.io)。