搞懂分布式技术19:使用RocketMQ事务消息解决分布式事务

  • 时间:
  • 浏览:0

假设先update DB成功,发送消息网络失败,重发又失败,如保会办? 

假设先发送消息成功,update DB失败。消息将会发出去了,又如此归还,如保会办?

但你你你这人 方案的两个多缺点只是:都要设计DB消息表,共同还都要两个多后台任务,不断扫描本地消息。因为消息的处里和业务逻辑耦合额外增加业务方的负担。

微信公众号【Java技术江湖】一位阿里 Java 工程师的技术小站。(关注公众号后回复”Java“即可领取 Java基础、进阶、项目和架构师等免费学习资料,更有数据库、分布式、微服务等热门技术学习视频,内容丰沛 ,兼顾原理和实践,另外也将赠送作者原创的Java学习指南、Java系统多多线程 员面试指南等干货资源)

         将会是将会收到消息了,而发送端认为如此收到,执行update db的回滚操作。则会因为A账号的钱如此扣,B账号的钱却加了。

也只是定义了两个多checkListener,RocketMQ会回调此Listener,从而实现底下所说的方案。

你你你这人 方案看似正确,虽然是错误的,因为有2:

对应你你你这人 极低概率的case,采取人工处里,会比实现两个多高复杂性的自动化回滚系统,更加可靠,也更加简单。

消费成功,但insert判重表失败,如保会办?关于你你你这人 ,在Kafka的源码分析系列,第1篇, exactly once大大问题的过后,有过讨论。

(2)把网络调用倒入DB事务底下,将会会将会网络的延时,因为DB长事务。严重的,会block整个DB。你你你这人 风险很大。

具体来说,只是把消息的发送分成了两个多阶段:Prepare阶段和确认阶段。

底下所说的消息底下件上注册的listener,超时过后该 回调producer的接口以选泽事务执行情况汇报

通过底下3步,没如此人基本就处里了这里update db和发送网络消息这两个多操作的原子性大大问题。

         基于以上分析,没如此人知道,你你你这人 方案虽然是错误的!

具体来说,底下的两个多步骤,被分解成两个步骤: 

(1) 发送Prepared消息 

(2) update DB 

(3) 根据update DB结果成功或失败,Confirm将会归还Prepared消息。

但这底下有个大大问题:A是先update DB,后发送消息呢? 还是先发送消息,后update DB?

那你你你这人 大大问题如保会处里呢?

至于消息表,虽然还是如此省掉。将会消息底下件要询问发送方,事物是是不是执行成功,还是都要两个多“变相的本地消息表”,记录事物执行情况汇报。

处里方案如下: 

(1)Producer端准备1张消息表,把update DB和insert message这两个多操作,倒入两个多DB事务底下。



消费失败了,重试,还一个劲失败如保会办?是后该 要自动回滚整个流程?

将会如此人会问了,前2步执行成功了,最后1步失败了如保会办?这里就涉及到了RocketMQ的关键点:RocketMQ会定期(默认是1分钟)扫描所有的Prepared消息,询问发送方,到底是要确认这条消息发出去?还是归还此条消息?

为了能处里该大大问题,共同又不和业务耦合,RocketMQ提出了“事务消息”的概念。

(3)Consumer端准备两个多判重表。处里过的消息,记在判重表底下。实现业务的幂等。但这里又涉及两个多原子性大大问题:将会保证消息消费 + insert message到判重表这两个多操作的原子性?

具体代码实现如下:

假设消息底下件如此提供“事务消息”功能,比如你用的是Kafka。那如保处里你你你这人 大大问题呢?

(1)网络的2将军大大问题:发送消息失败,发送方并告诉我是消息底下件真的如此收到消息呢?还是消息将会收到了,只是返回response的过后失败了?

(2)准备两个多后台系统多多线程 ,源源不断的把消息表中的message传送给消息底下件。失败了,不断重试重传。允许消息重复,但消息不必丢,顺序只是会打乱。

说到分布式事务,就会谈到那个经典的”账号转账”大大问题:两个多账号,分布位于两个多不同的DB,将会说两个多不同的子系统底下,A要扣钱,B要加钱,如保保证原子性?

一般的思路后该 通过消息底下件来实现“最终一致性”:A系统扣钱,过后 发条消息给底下件,B系统接收此消息,进行加钱。

答案是人工介入。从工程实践角度讲,你你你这人 整个流程自动回滚的代价是非常巨大的,不但实现复杂性,后该 引入新的大大问题。比如自动回滚失败,又如保会处里?

总结:对比方案2和方案1,RocketMQ最大的改变,虽然只是把“扫描消息表”你你你这人 事情,不必业务方做,只是消息底下件帮着做了。

如此人将会想到了,我想把“发送消息”你你你这人 网络调用和update DB倒入同两个多事务底下,将会发送消息失败,update DB自动回滚。从前不就保证两个多操作的原子性了吗?

将会如此人又要说了,无论方案1,还是方案2,发送端把消息成功倒入了队列,但消费端消费失败如保会办?

全都,这里下个结论: 我希望发送消息和update DB这两个多操作后该 原子的,无论谁先谁后,后该 有大大问题的。