如何解决下单系统这个高并发里边的分布式事务呢?
首先,我们肯定不会用 2PC 模式、 TCC-事务补偿性方案,我们也不考虑
最终我们选择可靠消息+最终一致性这种方式
为了保证高并发,订单这一块还是自己回滚,
库存服务自己怎么回滚?
有两种解决办法
第一种
我们在提交订单那里,当捕捉到异常要回滚的时候,给库存服务发一个消息,让库存服务自己把库存解锁
这样不需要让库存事务回滚,只需要给它发一个消息,不会损失什么性能
第二种
库存服务本身也可以使用自动解锁模式。
怎么自动解锁呢?
需要使用消息队列来完成。
如果你想让我这的哪些库存解锁,首先你需要给我发一个消息告诉我。
然后我们专门的库存解锁服务
,去来订阅我们stock.release.stock.queue
这个队列里的消息。
那你给我发消息的时候,比如:用路由键stock.release
,我知道要库存解锁,
然后,你的消息发给我们这个交换机stock-event-exchange
。
交换机把这个消息路由给stock.release.stock.queue
这个队列。
然后,这个队列stock.release.stock.queue
里边存的这些消息都是库存要解锁的消息,我们的库存解锁服务
只要收到了,它就会在后台慢慢的解锁消息。
我们不用保证强一致,我们哪怕是二十分钟、三十分钟,乃至于一天以后把这个库存解锁了,最终一致了就行。
所以我们可以来使用消息队列来完成我们的这个最终一致性。
锁库存的增强版逻辑
我们想要锁库存的话,我们先来保存一个库存工作单和库存工作单详情
相当于只要我们想要锁库存,我们先给数据库里边保存记录,我要锁库存。
接下来我们就来进行锁,只要锁成功了,那一切ok。
如果锁失败了,数据库里边相当于没有这个锁库存记录。
因为锁失败呢,我们这个本身自己所失败会全部回滚。
但如果可能是这种失败,比如我们来到订单里边,我们库存其实自己锁成功了。但是我们订单下边的其他完了,然后库存要进行解锁。那怎么办呢?
我们可以使用定时任务
订单服务的完整消息队列
库存自动解锁
库存微服务,有一个它的库存交换机stock-event-exchange
.
如果想要解锁库存,应该是这样的。
首先订单创建成功之后,库存锁定成功,然后发一个消息给交换机,
这个消息里面的内容有订单编号、仓库编号、哪个商品锁了几个库存,
这个交换机,绑定了两个队列,
一个是按照stock.release.#
模糊匹配的路由键绑定的stock.release.stock.queue
队列
一个是stock.delay.queue
队列
第一次发的库存锁定成功的消息,先使用路由键叫stock.locked
交换机按照这个路由键,找到stock.delay.queue
延时队列
延时队列50分钟以后,用stock.release
这个路由键,将死信交给库存交换机stock-event-exchange
,
交换机收到以后,按照这个路由键查找,发现stock.release.#
这个模糊匹配的路由键跟它是一样的,然后被交换机路由到我们这个stock.release.stock.queue
队列。
接下来的解锁库存服务,专门来处理stock.release.stock.queue
里的消息。
最终实现
柔性事务- 可靠消息+最终一致性方案(异步确保型)
使用MQ时保证消息可靠(丢失,重复,加压)和最终一致性。
7.24
7.23
定时关闭订单
首先订单创建成功之后,使用order.create.order
路由键将消息路由到order-event-exchange
交换机
交换机发现order.create.order
这个路由键绑定的是order.delay.queue
这个延时队列,然后就把它放到order.delay.queue
队列里
过了30分钟,这个延时队列里面的消息,也就是死信,通过order.release.order
又路由回order-event-exchange
交换机
然后交换机发现这个路由键对应的是order.release.order.queue
这个队列,然后就放到order.release.order.queue
这个队列里
最终监听order.release.order.queue
这个队列的释放订单服务,发现有消息进来了,就会针对里面的数据对其进行关闭订单
问题
这种关闭订单方式会有一些问题
假设订单创建成功之后,订单服务的机器由于卡顿、消息延迟等原因,导致订单未及时取消
此时库存服务的逻辑是订单创建成功之后,它自己会发一个消息,等 40分钟 以后检查之前下单的订单是否已取消,如果是已取消,则解锁库存
结果,库存服务过来查询时,订单服务由于上述原因没有将订单修改为已取消,所以库存就不会解锁,此时的库存消息就算是消费了
等库存服务都检查完了,此时的订单服务才反应过来,然后把订单状态改为已取消了,但是此时库存服务会再有任何的操作了,因为检查订单的消息已经被消费了,库存永远得不到解锁。
解决
为了解决这个问题,我们在监听取消订单的消息时,再发一个消息,主动解锁库存。
主动解锁库存
具体是这样的,在释放订单之后,我们主动发一个消息解锁库存,
使用order.release.other
将消息路由到交换机,
交换机根据order.release.other.#
匹配到stock.release.stock.queue
这个队列,并将消息发了过去,
库存服务有对这个队列进行监听,所有一旦有数据来了,就会对其进行解锁库存服务