消息队列(2)--如何利用事务消息实现分布式事务

2023-10-03 10:35:52 浏览数 (1)

1.怎么使用事务消息实现分布式事务

消息队列中的“事务”,主要解决的是消息生产者和消息消费者的数据一致性问题

应用场景:订单系统下订单后,需要在购物车系统清空购物车

事务消息适用的场景主要是那些需要异步更新数据,并且对数据实时性要求不太高的场景。比如我们在开始时提到的那个例子,在创建订单后,如果出现短暂的几秒,购物车里的商品没有被及时清空,也不是完全不可接受的,只要最终购物车的数据和订单数据保持一致就可以了。

方案:

1.TCC 2PC 3PC Saga(强一致性,并发量不发的情况下使用,比如下订单和使用优惠券)

2.可以使用本地消息表实现最终一致性(可以短时间接受不一致,前提是:异步执行的部分不依赖资源)

3.使用支持事务的消息中间件 RocketMQ Kafka(本地消息表思想的一种实现,使用起来更简单)

具体以方案3事务消息实现分布式消息为例:

1.开启事务

2.发送半消息

3.成功后执行本地事务,创建订单

4.本地事务执行成功,则提交事务;本地事务执行失败,则回滚事务

细心的同学发现步骤4:如果本地事务执行成功,提交事务的时候,请求失败了,怎么办?或者本地事务执行失败,回滚事务的时候失败了,怎么办?

Kafka给出的方案:简单粗暴,直接报错,用户可以重试(针对本地事务成功的情况),要不回滚之前本地事务成功的那部分(针对本地事务失败的情况)

Kafka 的解决方案比较简单粗暴,直接抛出异常,让用户自行处理。我们可以在业务代码中反复重试提交,直到提交成功,或者删除之前创建的订单进行补偿。

RocketMQ提供的方案:

提供了反查机制,需要业务代码提供接口

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

在我们这个例子中,反查本地事务的逻辑也很简单,我们只要根据消息中的订单 ID,在订单库中查询这个订单是否存在即可,如果订单存在则返回成功,否则返回失败。RocketMQ 会自动根据事务反查的结果提交或者回滚事务消息。

2.怎么保证消息顺序消费?

单个消息队列可以保证消息的有序性

在一个主题下的多个队列(分区)保证有序性,需要提供算法,相同订单id发到指定的队列,消费者占有这个队列进行消费即可

如果说,你的业务必须要求全局严格顺序,就只能把消息队列数配置成 1,生产者和消费者也只能是一个实例,这样才能保证全局严格顺序。

大部分情况下,我们并不需要全局严格顺序,只要保证局部有序就可以满足要求了。比如,在传递账户流水记录的时候,只要保证每个账户的流水有序就可以了,不同账户之间的流水记录是不需要保证顺序的。

如果需要保证局部严格顺序,可以这样来实现。在发送端,我们使用账户 ID 作为 Key,采用一致性哈希算法计算出队列编号,指定队列来发送消息。一致性哈希算法可以保证,相同 Key 的消息总是发送到同一个队列上,这样可以保证相同 Key 的消息是严格有序的。如果不考虑队列扩容,也可以用队列数量取模的简单方法来计算队列编号。

我正在参与2023腾讯技术创作特训营第二期有奖征文,瓜分万元奖池和键盘手表

0 人点赞