TCC(try-commit-cancel)
1、补偿性的事务,为了解决事务的最终一致性的问题,这种方案在支付宝里面有了10年的历史。
2、TCC是服务化的二阶段编程模型,其Try、Confirm、Cancel 3个方法均由业务编码实现;
- Try操作作为一阶段,负责资源的检查和预留。
检查和预留:比如现在有一个订单微服务还有一个库存的微服务。
比如现在购买商品的时候,比如购买10件商品,现在去查总的库存,在总的库存里面会有一个专门的库存,就是一个临时的东西来存储冻结的库存。这个冻结的库存是与订单相关的,会把原来购买的库存减去购买的数量。会冻结在程序当中,当真正的去提交的时候才会去对这个库存进行减。当Cancel的时候才会把这个库存又加回来。 - Confirm操作作为二阶段提交操作,执行真正的业务。
- Cancel是预留资源的取消。
3、TCC事务的Try、Confirm、Cancel可以理解为SQL事务中的Lock、Commit、Rollback。
在项目中应该避免分布式事务的问题,而不是制造分布式事务。
处理流程
为了方便理解,以订单和库存为例说明。
1、Try 阶段 从执行阶段来看,与传统事务机制中业务逻辑相同。但从业务角度来看,却不一样。TCC机制中的Try仅是一个初步操作,它和后续的确认一起才能真正构成一个完整的业务逻辑,这个阶段主要完成
- 完成所有业务检查( 一致性 )
- 预留必须业务资源( 准隔离性 )
- Try 尝试执行业务 TCC事务机制以初步操作(Try)为中心的,确认操作(Confirm)和取消操作(Cancel)都是围绕初步操作(Try)而展开。因此,Try阶段中的操作,其保障性是最好的,即使失败,仍然有取消操作(Cancel)可以将其执行结果撤销。
NOTE: 假设商品库存为100,购买数量为2,这里检查和更新库存的同时,冻结用户购买数量的库存,同时创建订单,订单状态设置为待确认状态。
2、Confirm / Cancel 阶段
根据Try阶段服务是否全部正常执行,继续执行确认操作(Confirm)或取消操作(Cancel)。Confirm和Cancel操作满足幂等性,如果Confirm或Cancel操作执行失败,将会不断重试直到执行完成,重试机制(可以用衰减的重试机制)+幂等特性。
NOTE:在TCC事务机制中,如果Try阶段能正常的预留资源,那么Confirm阶段一定能正确的提交。Comfirm阶段其实可以当做对Try阶段的补充,Try+Comfirm组成一个完整的业务逻辑。
Cancel阶段 当Try阶段存在服务执行失败,则进入Cancel阶段
TCC 事务应用场景
通过用户下单使用余额+红包支付来看一下TCC事务的具体应用。
假设用户下单操作来自3个系统下单系统、资金账户系统、红包账户系统,下单成功需要同时调用资金账户服务和红包服务完成支付
假设购买商品1000元,使用账户红包200元,余额800元,确认支付。
- Try操作
tryX 下单系统创建待支付订单
tryY 冻结账户红包200元
tryZ 冻结资金账户800元 - Confirm操作
confirmX 订单更新为支付成功
confirmY 扣减账户红包200元
confirmZ 扣减资金账户800元 - Cancel操作
cancelX 订单处理异常,资金红包退回,订单支付失败
cancelY 冻结红包失败,账户余额退回,订单支付失败
cancelZ 冻结余额失败,账户红包退回,订单支付失败。
方案总结
TCC事务机制相对于传统事务机制(X/Open XA),TCC事务机制相比于上面介绍的XA事务机制,有以下优点:
- 性能提升 具体业务来实现控制资源锁的粒度变小,不会锁定整个资源。
- 数据最终一致性 基于Confirm和Cancel的幂等性,保证事务最终完成确认或者取消,保证数据的一致性。
- 可靠性 解决了XA协议的协调者单点故障问题,由主业务方发起并控制整个业务活动,业务活动管理器也变成多点,引入集群。
缺点:TCC的Try、Confirm和Cancel操作功能要按具体业务来实现,业务耦合度较高,提高了开发成本。