连载中 4/18

TCC:把事务搬进业务代码

2026-06-15 · 1721 阅读 · 0 评论 · 0 赞

性能与侵入的交易

下单链路要跨订单、库存、账户三个服务,XA 一个数量级的吞吐折扣付不起,DBA 那句「用业务改造来换性能」就是出路:TCC(Try-Confirm-Cancel)——把 2PC 的两阶段从数据库层抬到业务层,锁不再由数据库行锁担任,改用业务字段自己表达。本篇先把模型立起来,三大坑留给下一篇。

三个接口各管一段

每个参与者从「一个接口」扩成「三个接口」:

Try:预留资源——不直接完成业务,而是把资源圈起来。账户服务 Try:校验余额充足,冻结 100 元(balance 不动,frozen 加 100);库存服务 Try:预占库存(可售减一,预占加一);订单服务 Try:生成「处理中」订单。

Confirm:确认提交——全部 Try 成功后逐个确认,用预留的资源真正完成业务:frozen 减 100(钱正式扣掉)、预占转真实扣减、订单状态改为已创建。Confirm 不允许再失败——它该做的检查和资源,Try 阶段已经都保证好了。

Cancel:取消释放——任一 Try 失败就逐个取消,把圈走的资源放回去:frozen 减 100、预占库存退回可售、订单标记关闭。

扣款一单的完整时序

Try    账户: 校验余额,frozen +100        (可提现余额不变)
Try    库存: 预占 +1,可售 -1
Try    订单: 生成「处理中」订单
  ↓ 全部成功
Confirm 账户: frozen -100(钱正式划走)
Confirm 库存: 预占 -1(转真实扣减)
Confirm 订单: 状态改为「已创建」
  ↓ 任一 Try 失败
Cancel  各方: 解冻、退预占、关订单

对照 2PC 看本质:Try 就是业务版的 prepare——都先把资源「握在手里」,但 2PC 握的是数据库行锁(锁着等全局指令),TCC 握的是业务字段里的冻结标记(不影响其他请求读余额、下别的单)。锁的粒度从「行」变成「该笔业务的部分资源」,阻塞消失,吞吐回来了。这就是业务改造换来的性能。

谁在当协调者

三阶段接口有了,谁来排时间表?事务管理器(框架层)负责:发起各参与者的 Try、收集结果、决定 Confirm 或 Cancel、处理超时、对失败的 Confirm/Cancel 持续重试。落地上可以用 Seata 的 TCC 模式(第 11 篇统一讲),也可以轻量自研——发起方一个状态表加定时任务,就是最朴素的协调者。纪律只有一条:Confirm 和 Cancel 必须设计成可重入——框架的重试没有任何一次保证只调一次,重试风暴是常态不是异常。

Try 的预留粒度怎么定

预留资源的形态因业务而异,老王总结了三种常见姿势:字段冻结(金额冻结、预占库存,最典型);状态占位(生成处理中订单、预创建记录);额度标记(外部系统额度预扣、券核销预占)。粒度设计的原则是 Try 要「够便宜、可释放」——预留本身不产生资损、不过期失效、Cancel 能一键还原。凡是 Try 里就开始真实扣减的,都是设计错了。

TCC 的得与失

维度2PC/XATCC
锁机制数据库行锁,全局阻塞业务冻结标记,无全局阻塞
吞吐低(掉一个数量级)高(接近本地事务)
业务侵入无(改配置)每个参与者三个接口
一致性强一致最终一致(Confirm 前可见冻结态)
开发成本低高(含幂等、防悬挂全套纪律)

适用场景由此清晰:资源占用型、高并发、资金敏感的短事务——支付冻结、预占库存、额度预扣。长流程多环节的编排场景,TCC 三接口会膨胀成十几个,那是 Saga 的地盘(第 6 篇)。

小结

TCC 一句话:Try 预留、Confirm 确认、Cancel 释放,把 2PC 的锁从数据库行抬到业务字段,性能换侵入;Confirm 与 Cancel 天生要被重试,幂等纪律从写第一个接口起就要立。重试只是三大坑之一——空回滚、幂等、悬挂这三兄弟怎么防,下一篇逐个拆解。

☕
503

10 年全栈工程师 · 503咖啡馆主理人

#分布式事务#TCC#Try-Confirm-Cancel#资源预留#最终一致

评论 (0)

热门推荐

连载中 11/22

主从搭建实操:从零配出一主两从

光讲原理不过瘾?手把手搭一主两从:my.cnf 六个参数、复制账号、GTID、CHANGE REPLICATION SOURCE TO、SHOW REPLICA STATUS 验收,附翻车排查清单。

#MySQL#主从复制#GTID#主从搭建#高可用
2026-05-07 · 10101 阅读 · 0 评论 · 0 赞
连载中 16/22

连接池:HikariCP 参数与连接风暴

连接池不是越大越好:8 核机器配 1000 连接反而更慢的数学原理,HikariCP 四个必调参数,maxLifetime 与 wait_timeout 的隐形陷阱。

#MySQL#连接池#HikariCP#maxLifetime#连接风暴
2026-05-10 · 9873 阅读 · 0 评论 · 0 赞
连载中 4/16

缓存穿透:恶意 ID 打穿 MySQL 的四道防线

请求的数据在缓存和数据库里都不存在时,缓存形同虚设。聊聊参数校验、空值缓存、布隆过滤器、限流熔断四道防线的原理与组合打法。

#Redis#缓存穿透#布隆过滤器#高可用
2026-05-16 · 9294 阅读 · 21 评论 · 287 赞