基于真实电商的下单扣库存学习理解分布式事务解决方案

这里是weihubeats,觉得文章不错可以关注公众号小奏技术,文章首发。拒绝营销号,拒绝标题党

业务背景

我们这里将业务简化为最简单的下单扣库存逻辑,不去关注其他分支部分来理解整个电商下单扣库存的解决方案

分布式事务解决方案及缺点

  • 最终一致性:异步解决方案,数据同步有延迟。性能高
  • TCC(try、Confirm、Cancel):同步解决方案,正常需要两个阶段(try、Confirm),对性能损耗较大
  • 事务状态表:同步方案,但需要每次记事务流水表、更新事务状态,比较繁琐和TCC类似,性能也有较大消耗
  • 异步对账:也是一个异步过程,需要后台定时器去对账补全数据

这里就不详细介绍每种解决方案的场景和使用了

业务过程分析

下单至少包含的两种操作:

  1. 创建订单
  2. 扣减库存

image-20220123160408659

这里的订单和库存之间的调用故意画成双向的,客户端故意两个服务都调用,后面会具体分析

下单扣减库存的业务难点

  1. 需要同步执行,扣减库存的结果需要立即知道,否则会发生超卖违约
  2. 需要很高的性能

可以看到需要同步执行,又要高性能,所以TCC和事物状态表异步对账这几种方案就可以排除了。既要高性能又要强一致性,鱼和熊掌本就不可兼得。但是我们基于业务本身去分析,会发现有一个很关键的特点

不允许超卖,但是允许少卖,就是我们可以多扣库存不能少扣库存。比如100件商品我们可以买出99件,有1件没卖出去是可以接受的,但是如果100件商品卖给101人,其中有一个人收不到货就可能造成平台违规不能接受(具体业务场景具体分析,有些业务场景可能也能接受比如,故意超卖及时补货等,但这里就以上面说的不允许超卖为业务前提)。

解决方案

1. 先扣库存,后创建订单

会有如下三种情况发生

  1. 扣库存成功,创建订单成功。返回结果成功
  2. 扣库存成功,创建订单失败。返回结果失败。调用方重试(出现多扣减库存,多创建订单)
  3. 扣库存失败,不再创建订单。返回结果失败。调用方重试
情况 扣库存 创建订单 返回结果 影响
1 成功 成功 成功
2 成功 失败 失败 多扣库存、多创建订单
失败 失败

注意 扣库存和创建订单是不同的事务,不能放在通一个事务中,因为存在网络两将军问题

2. 先创建订单,后扣库存

也会有如下三种情况

  1. 创建订单成功,扣减库存成功,返回结果成功
  2. 创建订单成功,扣库存失败。调用方重试(可能出现多扣减库存)
  3. 创建订单失败,不再扣库存。返回结果失败。
情况 创建订单 扣库存 返回结果 影响
1 成功 成功 成功
2 成功 失败 失败 多扣库存,多创建订单
3 失败 失败

这里情况2为什扣库存失败了还会存在多扣库存的情况呢?因为这里的失败分两种,一种是库存系统真的扣库存失败,第二种就是库存扣成功了,可能因为网络原因导致订单系统认为扣失败了。详细情况可以了解网络两将军问题

先创建订单的方式可能出现订单创建成功,然后库存失败,导致创建了订单而库存未扣减。所以这种方案并不合适,除非将扣减库存和创建订单放在一个事务中,那又变成了先扣减库存,如果放在通一个事务。最坏的情况也是多扣减库存

异常数据处理

可以看到两种方案都会出现多扣减库存,那么如何处理这些异常数据呢?

1. 库存表流水表

  1. 在每次扣减库存的时候都去生成一条库存流水记录表,状态为占用,订单支付成功后,将状态改为释放
  2. 定时库存对账去扫描那些长时间状态为占用不释放的库存流水,根据订单状况看看是因为多扣的库存还是未支付的库存,然后将这些订单取消

2. 重试+回滚+报警+人工介入

上面的解决方案还是需要去维护一个多的库存流水表,然后去修改状态。如果需要更为简单使用的方案,就是通过重试+回滚+报警+人工介入。

基于方案 先扣库存,后创建订单。我们不作状态补偿,添加重试、报警、回滚、人工介入

具体流程

image-20220123171747918

可以看到虽然最后还是要人工介入,但是很明显这种方案是很实用的。

不过这种方案在非常极端的情况可能存在回滚库存的时候系统宕机还是会多扣库存。其次在第一次扣库存存在多扣库存也无感知,肯定需要添加一个扣库存记录表(如果有MQ就先发一条延时消息),这里也就没画出来了,因为要注意细节太多了

可能上面的流程还涉及分布式锁等各种其他操作,这里就不重点展开了。因为主要是分析分布式事务的一种解决方案

如果想要更为稳妥的实现方案,可以基于消息中间件解决,比如RocketMQ的事务消息,具体实现方式可以参考这里

[分布式事务之可靠消息最终一致性RocketMQ实现落地] blog.csdn.net/qq_42651904…

总结

总的来说分布式事务的解决方案有很多,每种解决方案都适用于不同的场景,大家在解决使用的时候还是需要结合业务来选择具体的解决方案,没有最好的方案,只有最适合的 然后最重要的就是要记住所有的其他系统的调用都要有检查回滚操作

猜你喜欢

转载自juejin.im/post/7056338980781948942