记录基于RabbitMQ消息队列的分布式事务解决方案 - MQ分布式消息中间件实战,seata以外的分布式事务实现方式

1、极速了解MQ

        介绍Rabbitmg用于解决分布式事务必须掌握的5个核心概念 一款分布式消息中间件,基于erlang语言开发, 具备语言级别的高并发处理能力。和Spring框架是同一家公司。支持持久化、高可用 。

核心5个概念: 

  • Queue: 真正存储数据的地方
  • Exchange: 接收请求,转存数据 
  • Bind: 收到请求后存储到哪里 
  • 消息生产者:发送数据的应用 
  • 消息消费者: 取出数据处理的应用 

2、分布式事务问题 

分布式事务是一个业务问题,不能脱离具体的场景。

2.1 分布式事务的几种解决方案

  • 基于数据库XA/ JTA协议的方式

        需要数据库厂商支持; JAVA组件有atomikos等

  •  异步校对数据的方式

        支付宝、微信支付主动查询支付状态、对账单的形式;

  •  基于可靠消息(MQ)的解决方案

        异步场景;通用性较强;拓展性较高

  •  TCC编程式解决方案

        严选、阿里、蚂蚁金服自己封装的DTX(Distributed Transaction),包含了阿里开源的seata分布式事务框架等。

我主要学习和理解学会基于可靠消息来解决分布式事务问题。

eg:美团点评系统架构

2.2 多系统间的分布式事务问题

1、用户下单生成订单:

2、需要传递订单数据,由此产生两个事务一致性的问题

数据不一致的案例:

当接口调用失败时,订单系统事务回滚,提示用户操作失败

误以为这样的接口调用写法,就不会有分布式事务问题

接口调用成功或者失败,都可能会产生分布式事务问题:

  1. 接口调用成功,订单系统数据库事务提交失败,并没有通知运单系统回滚事务,产生数据不一致。
  2. 网络原因接口调用超时,订单系统抛出异常数据库事务回滚,但是运单系统接口继续执行,产生数据不一致。

上述两种情况,都会导致数据不一致的问题。

3、实现分布式事务 - 五步法

通过MQ解决分布式事务的5个步骤, 以及分布式事务处理中要注意的地方

  • 之前都是订单系统发送HTTP请求运单系统的接口,出问题了!

  • 因此我们考虑发消息给MQ, 异步暂存!

3.1 整体设计思路

外卖下订单后,可以慢慢等待运单中心数据生成,并非强制要求同时性

  1. 可靠生产:保证消息一定要发送到Rabitmq服务(下文讲解)
  2. 可靠消费:保证消息取出来一定正确消费掉(下文讲解)

最终使多方数据达到一致。

3.2 步骤1 - 可靠的消息生产记录消息发送

  • 存在隐患 - 可能消息发送失败呀!

为了确保数据一定成功发送到MQ。

在同一事务中,增加一个记录表的操作, 记录每一条发往MQ的数据以及它的发送状态

于是我们在订单系统中增加一个本地信息表:

于是在代码实践中,不再通过HTTP接口调用运单系统接口,而是使用MQ!

生成订单时,也保存本地信息表,例如存储订单的唯一标识(id、订单号)。

3.3 步骤2 - 可靠消息生产(修改消息发送状态)

  • 利用RabbitMQ事务发布确认机制(confirm),开启后,MQ准确受理消息会返回回执 

  • 然后就能根据回执信息判断如何更新本地信息表了

确保在SpringBoot中开启rbmq的Confirm机制:

  • 如果出现回执没收到、消息状态修改失败等特殊情况

兜底方案:定时检查消息表,超时没发送成功,再次重发

3.4 步骤3 - 可靠消息处理(正常处理)

  • 运单系统收到消息数据后,突然宕机,或者访问运单DB时,DB突然宕机,消息数据不就丢了吗!!!

于是需要以下特性:

幂等性

防止重复消息数据的处理,一次用户操作,只对应一次数据处理。

开启手动ACK模式

由消费者控制消息的重发/清除/丢弃

3.5 步骤4 - 可靠消息处理(消息重发)

消费者处理失败,需要MQ再次重发给消费者。

出现异常一般会重试几次,由消费者自身记录重试次数,并进行次数控制(不会永远重试!)

3.6 步骤五 - 可靠消息处理(消息丢弃)

消费者处理失败,直接丢弃或者转移到死信队列(DLQ)

重试次数过多、消息内容格式错误等情况,通过线上预警机制通知运维人员!!(极端情况)

4 总结及扩展

4.1 MQ方案的优点和缺点

优点:

  1. 通用性强
  2. 拓展性强
  3. 方案成熟

缺点:

  1. 基于消息中间件,只适合异步场景
  2. 消息处理会有延迟,需要业务上能够容忍

开发中注意点:

  • 尽量避免分布式事务;
  • 尽量将非核心事务做成异步;
  • 保证事务的ACID四大原则;

实现分布式事务有很多种方式,看大家习惯用哪一种,使用消息中间件是一种很基本也很可靠的方式。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
RabbitMQ的延迟队列可以用于实现分布式事务。在分布式事务中,事务发起方将消息发送到消息中间件(如RabbitMQ),事务参与方从消息中间件接收消息。网络通信的不确定性可能导致分布式事务问题。为了解决这个问题,可以使用RabbitMQ的延迟队列。 延迟队列可以通过设置消息的TTL(Time To Live)来延迟消息的投递时间。当消息的TTL过期后,消息会被发送到死信交换机(Dead Letter Exchange)。通过结合消息的TTL和死信交换机,可以实现分布式事务的延迟处理。 具体实现方法是,在事务发起方将消息发送到延迟队列时,设置消息的TTL为期望的延迟时间。当延迟时间过期后,RabbitMQ会将消息发送到死信交换机,而事务参与方可以从死信交换机接收消息并进行相应的处理。 使用RabbitMQ的延迟队列实现分布式事务可以有效地减少系统内存消耗、降低数据库压力,并减小时间误差的影响。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [分布式事务(延时队列RabbitMQ)](https://blog.csdn.net/m0_55990500/article/details/127428422)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [RabbitMQ延时队列解决分布式事务问题](https://blog.csdn.net/java123456111/article/details/122925838)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值