TCC(Try-Confirm-Cancel)是一种在业务层面实现的分布式事务解决方案,它通过业务逻辑的主动补偿来保证数据的最终一致性。与依赖数据库锁的强一致性方案(如2PC)不同,TCC将事务的控制权交给了业务代码,因此在高并发场景下具有更高的性能和灵活性。
🤔 TCC 是如何工作的?
TCC 的核心思想是将一个分布式事务拆分为三个明确的阶段,每个参与的服务都需要实现这三个阶段的逻辑。
-
Try(尝试)阶段
- 目的:进行业务检查和资源预留。
- 行为:检查业务参数是否合法、资源是否充足。如果检查通过,则“预留”或“冻结”所需资源,但不真正执行最终的业务操作。例如,在支付场景中,Try 阶段会冻结用户账户中的相应金额,而不是直接扣款。
- 结果:所有参与者的 Try 阶段都成功,事务才能进入 Confirm 阶段;只要有任意一个失败,则直接进入 Cancel 阶段。
-
Confirm(确认)阶段
- 目的:确认并执行最终的业务操作。
- 行为:在所有 Try 阶段成功后,协调者会通知所有参与者执行 Confirm 操作。此时,参与者会使用 Try 阶段预留的资源,完成真正的业务逻辑。例如,将冻结的金额正式扣除,并更新收款方余额。
- 特点:Confirm 操作必须保证幂等性,即无论被调用多少次,结果都是一致的,以应对网络重试等异常情况。
-
Cancel(取消)阶段
- 目的:释放 Try 阶段预留的资源,进行补偿回滚。
- 行为:如果任何一个参与者的 Try 阶段失败,或者在 Confirm 阶段出现异常,协调者会通知所有参与者执行 Cancel 操作。参与者需要释放 Try 阶段预留的资源,使系统状态恢复到事务开始之前。例如,解冻用户在 Try 阶段被冻结的金额。
- 特点:与 Confirm 一样,Cancel 操作也必须是幂等的。
流程示例:电商下单
以用户下单为例,涉及订单、库存、支付三个服务:
- Try:订单服务创建“待确认”订单;库存服务预占商品库存;支付服务冻结用户余额。
- Confirm:所有 Try 成功后,订单状态更新为“已确认”;库存服务正式扣减预占的库存;支付服务正式扣款。
- Cancel:若任一 Try 失败(如库存不足),则订单服务取消订单;库存服务释放预占的库存;支付服务解冻用户余额。
📊 TCC 与 2PC 有何不同?
TCC 和 2PC(Two-Phase Commit)都是两阶段提交,但它们在实现层面和性能上有本质区别。
| 对比维度 |
2PC (Two-Phase Commit) |
TCC (Try-Confirm-Cancel) |
| 锁定机制 |
资源层(数据库)长期锁定 |
业务层短暂预留 |
| 一致性 |
强一致性 |
最终一致性 |
| 侵入性 |
无侵入(基于数据库XA协议) |
高侵入(需改造业务代码) |
| 性能 |
较低(同步阻塞) |
较高(无长事务锁) |
| 资源支持 |
仅支持XA协议的数据库 |
支持任意资源(DB, Redis, API等) |
简单来说,2PC 是数据库层面的“强一致性”事务,会长时间锁定资源,影响并发性能。而 TCC 是业务层面的“柔性事务”,通过短暂的资源预留,大大提升了系统的可用性和吞吐量。
📌 TCC 的优缺点与适用场景
优点
- 高性能:没有长时间的资源锁定,并发度高,适合高并发场景。
- 高灵活:完全由业务代码控制,可以适配数据库、缓存、第三方API等多种异构资源。
- 一致性可控:通过明确的 Confirm/Cancel 补偿逻辑,可以保证数据的最终一致性。
缺点
- 开发成本高:每个业务操作都需要实现 Try、Confirm、Cancel 三个接口,代码量翻倍。
- 业务侵入性强:需要将原有的业务逻辑改造为“预留-确认”模式,对业务代码有较大改动。
- 实现复杂:开发者必须手动处理幂等、空回滚(Cancel先于Try执行)、业务悬挂(Try晚于Cancel执行)等复杂的边界情况。
适用场景
TCC 非常适合对性能和一致性都有较高要求的短流程核心业务,例如:
- 电商下单、秒杀
- 金融支付、转账
- 任何需要跨服务、跨资源类型且支持“资源预留”语义的业务场景。