分布式事务--消息表+MQ--使用/方案

原文网址:分布式事务--消息表+MQ--使用/方案_IT利刃出鞘的博客-CSDN博客

简介

本文介绍分布式事务的一种解决方案:消息表结合MQ。

本地消息表+MQ(无事务)

简介

说明

项目来源

源于eBay经典的BASE方案。ebay的完整方案BASE: An Acid Alternative - ACM Queue

基本设计思想

将远程分布式事务拆分成一系列的本地事务

使用的重要技术

消息队列和消息应用状态表

优缺点

优点:基本避免了分布式事务,实现了“最终一致性”;开发简单
缺点:需设计DB消息表,同时还需要一个后台任务,不断扫描本地消息。导致消息的处理和业务逻辑耦合额外增加业务方的负担。

适用场景

适用于对一致性要求不高的非高并发场景。(本地消息队列是BASE理论,是最终一致模型)。

实例流程

说明:这种分布式事务适合前边服务弱依赖于后边的服务的场景,比如付款成功增积分:积分的多少不影响付款。但对于强依赖的情况不合适,如下单减库存操作:是否能下单由库存是否充足而定,而下单是否成功由减库存是否成功而定,此时,用此法最合适:订单模块直接调用减库存的微服务接口。

本处以购物时的付款成功增积分为例说明。

 

错误处理

  • 步骤:1,2:任意一个出错,整个事务回滚,不会出错
  • 步骤3:投递消息成功,结果接收MQ响应时网络出错。不会出错
  • 步骤4:MQ宕机(解决方法:MQ一般支持持久化)。消费者消费失败(解决方法:重试3次)
  • 步骤4-8:4-8任意一个失败次数超过重试次数。解决方法:发送报警,让人工处理。
            从工程实践角度讲,这种整个流程自动回滚的代价是非常巨大的,不但实现复杂,还会引入新的问题。
    比如自动回滚失败,又怎么处理?对应这种极低概率的case,采取人工处理,会比实现一个高复杂的自动化回滚系统,更加可靠,也更加简单。
  • 步骤6:增积分完成之后,断网,导致增积分成功的消息没有发布出去。解决方法:定时任务会再次将消息投递,步骤5会判断到增积分已完成,直接跳到步骤8:发布消息
  • 一个原子性问题:如果保证消息消费 + insert message到判重表这2个操作的原子性?消费成功,但insert判重表失败,怎么办?关于这个,在Kafka的源码分析系列,第1篇,exactly once问题的时候,有过讨论。

MQ(有事务)

简介

上边“本地消息表+MQ(无事务)”的一个缺点:需要设计DB消息表,同时还需要一个后台任务,不断扫描本地消息。导致消息的处理和业务逻辑耦合额外增加业务方的负担。

为了能解决该问题,同时又不和业务耦合,RocketMQ提出了“事务消息”的概念。阿里巴巴的RocketMQ中实现了分布式事务,实际上其实是对本地消息表的一个封装,将本地消息表移动到了MQ内部

对比方案3和方案2,RocketMQ最大的改变,其实就是把“扫描消息表”这个事情,不让业务方做,而是消息中间件帮着做了。至于消息表,其实还是没有省掉。因为消息中间件要询问发送方,事物是否执行成功,还是需要一个“变相的本地消息表”,记录事物执行状态。

具体来说,就是把消息的发送分成了2个阶段:Prepare阶段和确认阶段。
具体来说,上面的2个步骤,被分解成3个步骤:

  • 第一步:生产者:向RocketMQ发送Prepared消息,生产者会拿到消息的地址。
  • 第二步:生产者:执行本地事务(修改数据库的数据)。
  • 第三步:生产者:
      若第二步执行成功,用第一步拿到的地址去访问消息,并修改状态(Confirm),消息接收者就能使用这个消息。
      若第二步执行失败,用第一步拿到的地址去访问消息,并取消Prepared消息,消息接收者就得不到这个消息。

 

1. Producer向broker端发送消息
2. 服务端将消息持久化成功之后,向发送方ACK确认消息已经发送成功,此时消息为半消息
3. 发送方开始执行本地事务逻辑
4. 发送方根据本地事务执行结果向服务端提交二次确认(Commit或者Rollback)。服务端收到Commit状态则将半消息标记为可投递,订阅方最终将收到该消息;服务端收到Rollback状态则删除半消息,订阅方将不会接受该消息。
5. 在断网或者是应用重启等特殊情况下,上述步骤4提交的二次确认最终未到达服务端,RocketMQ 会定期扫描消息集群中的事物消息,若发现未经确认的Prepared 消息,会对该消息发起消息回查
6. 发送方收到消息回查后,需要检查对应消息的本地事务执行的最终结果
7. 发送方根据检查得到的本地事务的最终状态再次提交二次确认,服务端仍按照4对半消息进行操作

错误处理

消费方重试全部失败怎么办?

解决方法:发送报警,让人工处理。

从工程实践角度讲,这种整个流程自动回滚的代价是非常巨大的,不但实现复杂,还会引入新的问题。

比如自动回滚失败,又怎么处理?对应这种极低概率的case,采取人工处理,会比实现一个高复杂的自动化回滚系统,更加可靠,也更加简单。

实例

其他网址

RocketMQ分布式事务消息_盲流子的博客-CSDN博客
RocketMQ使用及分布式事务解决思路_数据库_易水寒的博客-CSDN博客

官方Springboot RocketMQ例子:https://github.com/ThierrySquirrel/rocketmq-spring-boot-starter

其他网址

分布式事务之本地消息表_大数据_weixin_34327223的博客-CSDN博客
分布式事务-本地消息表 | Echo Blog
分布式事务--本地消息表(定时轮询扫描)_Java_王卫东的博客-CSDN博客
分布式事务探讨系列(三):本地消息表和MQ等可靠消息解决方案_数据库_lsblsb的专栏-CSDN博客

RocketMQ使用及分布式事务解决思路_数据库_易水寒的博客-CSDN博客
分布式事务-本地消息表 | Echo Blog        

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT利刃出鞘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值