什么是分布式事务?

首先事务是要保证我们对一系列数据进行一些操作,这些操作要么都成功,要么都失败。一个严格意义的事务实现,应该具有 4 个属性:原子性、一致性、隔离性、持久性。

但是,对于分布式系统来说,严格的实现 ACID 这四个特性几乎是不可能的。一般会采用一些“妥协”的方案,比如说顺序一致性或者最终一致性。

消息队列是如何实现分布式事务的?

一个订单和购物车的模型如下图:

image-20230501183227849

这里的半消息,并不是只发送数据信息的一半,而是说发送全部的数据,但是在事务提交之前,消费者是无法看到这条数据的。

这里,发送半消息后,就可以继续执行创建订单,如果订单创建成功,则提交事务,那么消费者,也就是购物车模块可以看到这条消息,然后从购物车删除对应订单的物品。如果订单创建失败,则消费者无法看到消息,也就不会导致创建订单失败,但是购物车删除物品这种情况。

但是还存在一个问题:如果提交事务消息失败时,还是会存在一定的问题,针对这个问题,Kafka 和 RocketMQ给出了不同的解决办法。Kafka 的解决方案比较简单粗暴,直接抛出异常,让用户自行处理。我们可以在业务代码中反复重试提交,直到提交成功,或者删除之前创建的订单进行补偿。RocketMQ 则给出了另外一种解决方案。

RocketMQ 中的分布式事务实现

在 RocketMQ 中的事务实现中,增加了事务反查的机制来解决事务消息提交失败的问题。如果 Producer 也就是订单系统,在提交或者回滚事务消息时发生网络异常,RocketMQ 的 Broker 没有收到提交或者回滚的请求,Broker 会定期去 Producer 上反查这个事务对应的本地事务的状态,然后根据反查结果决定提交或者回滚这个事务。

为了支撑这个事务反查机制,我们的业务代码需要实现一个反查本地事务状态的接口,告知 RocketMQ 本地事务是成功还是失败。

image-20230501184354506

参考

《消息队列高手课》