略难的题,因为你要掌握两个东西:状态流转和对应的补偿任务。
那么很多人在听到这个问题的时候,第一个念头就是我执行一条 INSERT 语句不就好了?这样回答就肯定寄了,因为在微服务架构下,你要考虑到订单是一个服务,库存是另外一个服务,你得保证创建订单-锁定库存一起成功或者一起失败。
参考 如何设计一个秒杀系统? - 面试ICU (mianshi.icu)
这个问题问的就是秒杀消费者在消费消息的时候,究竟做了一些什么。因此你本质上是要解释清楚,在微服务架构下你是如何创建订单、锁定库存的,并且要进一步解决这个过程中的部分失败问题。
在整个机制里面,要注意处理部分失败的问题。这个部分失败包括两种情况:
在遇到这种部分失败的情况下,首先可以考虑重试。但是经过重试之后还是有可能都失败了。在这种情况下,可以引入补偿任务来解决问题。
补偿任务的逻辑是,找到长期处于 INIT 或者 CREATED 状态的订单,而后根据 order_sn 或者 key 去找对应的锁定库存的记录。如果要是发现存在相应的锁定记录,那么就释放库存。
扫描找订单,反查库存表,存在则释放,订单改失败
深入分析了部分失败的问题
订单超时未支付取消;
整个部分失败的解决思路就是典型的状态驱动 + 补偿任务的模式的应用。在大部分的分布式系统中,分布式事务场景或者追求最终一致性的场景都可以用这个思路来解决。它的基本理念就是:业务都可以看做是从一个状态迁移到另外一个状态,而部分失败就是这种迁移失败了。
比如说我曾经设计过的一个本地消息表解决方案,就是采用了同样的思路。这个方案是为了解决业务成功一定要发送成功消息这种典型的场景,那么我的思路就是插入一条发送记录,此时状态是 INIT。这个插入记录的动作要和业务操作保持在一个本地事务中,确保插入记录和业务操作满足 ACID 的特性。
总结状态驱动+补偿任务模式
ACID;本地消息表解决方案;