自己实现TCC方案解决普通交易环节订单和库存的一致性

TCC简介

TCC(Try-Confirm-Cancel)是一种基于业务补偿的分布式事务解决方案 ,核心思想通过三个阶段保证分布式事务的一致性:

1. Try(尝试)

各参与服务预执行业务检查(资源预留),如库存冻结、账户余额预扣等

2. Confirm(确认)

所有Try成功时,协调者触发Confirm操作,各服务正式提交事务(如实际扣减库存、划转金额)。

3. Cancel(取消)

任一Try失败时,协调者触发Cancel操作,各服务回滚Try阶段的预留资源(如解冻库存、返还预扣金额)。

为什么可普通交易可以用TCC

因为作为普通交易(normalBuy),主要处理的是非秒杀流量,那么就意味着没有热点问题,那么就是下单的时候同步处理库存扣减和创建订单即可,然后再异步更新redis的库存。

相比于秒杀的方案,秒杀方案不管是哪种,其实都是数据库的扣减和订单创建都是在异步链路上的,通过重试来保证最终一致性的。而普通交易没有这个重试机制,那么我们就引入TCC来保障一致性。

普通交易的TCC如何拆解

那么,映射到我们的交易下单流程中,主要涉及到商品和订单两个模块,那么分别作TCC的话,可以按照以下方式进行拆解:

Try

  • 订单:预创建订单,订单状态未CREATE,用户看不到,也无法支付
  • 商品(库存):冻结库存,被冻结的库存无法下单,只能解冻

Confirm

  • 订单:确认订单,从CREATE推进到CONFIRM,这时候订单就可以支付了,用户也能看到
  • 商品(库存):解冻并扣减库存(原子操作)

Cancel(Try后的Cancel)

  • 订单:废弃订单,从CREATE推进到DISCARD,用户看不到,也做任何操作
  • 商品(库存):解冻库存,被解冻的库存就可以下单了。

Cancel(Confirm后的Cancel)

  • 订单:废弃订单,从CONFIRM推进到DISCARD,用户看不到,也做任何操作
  • 商品(库存):回退被扣减的库存。

具体流程有以下5种情况:

1、Try失败,Cancel成功

2、Try失败,Cancel失败

3、Try成功,Confirm成功

4、Try成功,Confirm失败,Cancel成功

5、Try成功,Confirm失败,Cancel失败

这里面的2种Cancel失败的情况,一般只会在系统异常的时候才会发生,比如数据库挂了,应用挂了等等,所以我们可以考虑通过MQ的方式来进行Cancel,这样如果失败了,MQ可以不断重试。

而且Cancel的操作放在异步链路上,就可以更好的保障同步下单链路的稳定性,异步回退稍微晚一点其实影响不大。

所以,我们重点看上面的1、3、4三种情况。

为了解决空回滚和悬挂的问题,我们引入了事务日志的机制,通过 MySQL 的本地事务来保证业务操作和事务日志的写入的原子性。

详细说明请参考:

引入事务表解决SEATA的TCC模式的空回滚和悬挂问题-CSDN博客https://blog.csdn.net/jonas80029735/article/details/147316010?sharetype=blogdetail&sharerId=147316010&sharerefer=PC&sharesource=jonas80029735&spm=1011.2480.3001.8118

TCC的几种情况

Try-Cancel:

第一种最简单,就是Try失败了,然后执行Cancel:

这个情况下,我们为了不让Cancel在同步链路上占用接口耗时,并且Cancel的回退晚一点也没关系,所以我们通过MQ来做Cancel的异步处理,并且利用MQ的重试机制来保证Cancel的最终处理成功。

Try-Confirm:

这个链路其实是系统中流量最大的链路,大部分场景都是走的这个分支,即Try和Confirm都能成功。

这个过程全部同步,代码执行完之后,将全部处于Confirm状态,数据是一致的。

Try-Confirm-Cancel:

这个是另外一个情况, 就是Try成功了,但是Confirm的时候有人失败了。

这个就稍微复杂一点了。前面的try成功,之后confirm失败了,但是为了提升Confirm成功率,避免因为网络延迟、网络抖动带来的大量回滚,我们会尽最大努力的进行confirm,因为try都成功了,confirm成功的概率是非常大的。所以我们引入了重试的机制。

但是如果3次重试之后还是失败,那就要启动cancel的流程了,同样我们把cancel也放到了MQ的异步链路上。

但是为了避免在cancal消息接到的时候,confirm又成功了,所以cancel这里会先发一个疑似废单消息,在这个消息里再检查一下订单状态,如果成功了,则不需要执行了。如果没成功,则再走Try-Cancel的废单流程。

这里面需要注意的是,对于订单、商品(藏品、盲盒)系统模块来说,他们是不关心这个疑似废单消息的,这个消息交易模块自己包掉。他们只关心真正的废单消息的处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

埃泽漫笔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值