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

  • 时间:
  • 浏览:1
  • 来源:彩神IOS下载_神彩IOS下载官方

(1)网络的2将军问题:发送消息失败,发送方并问你是消息底下件真的没法收到消息呢?还是消息机会收到了,某些返回response的以前失败了?

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



某些,这里下个结论: 而且我发送消息和update DB这十个 多操作全部前会原子的,无论谁先谁后,全部前会有问题的。

消费失败了,重试,还一个劲失败缘何办?是全部前会要自动回滚整个流程?

至于消息表,虽然还是没法省掉。机会消息底下件要询问发送方,事物是否执行成功,还是需要十个 多“变相的本地消息表”,记录事物执行情况。

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

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

具体代码实现如下:

为了能正确处理该问题,并肩又不和业务耦合,RocketMQ提出了“事务消息”的概念。

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

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

假设先发送消息成功,update DB失败。消息机会发出去了,又不能注销,缘何办?

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

村里人 机会想到了,我能把“发送消息”你这些网络调用和update DB中放去同十个 多事务底下,机会发送消息失败,update DB自动回滚。另十个 多不就保证十个 多操作的原子性什么时间?



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

         机会是机会收到消息了,而发送端认为没法收到,执行update db的回滚操作。则会原因分析分析 A账号的钱没法扣,B账号的钱却加了。

正确处理方案如下: 

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

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

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

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

(2)把网络调用中放去DB事务底下,机会会机会网络的延时,原因分析分析 DB长事务。严重的,会block整个DB。你这些风险很大。

假设消息底下件没法提供“事务消息”功能,比如你用的是Kafka。那要怎样正确处理你这些问题呢?

答案是人工介入。从工程实践深层讲,你这些整个流程自动回滚的代价是非常巨大的,不但实现复杂,前会引入新的问题。比如自动回滚失败,又缘何正确处理?

机会村里人 又要说了,无论方案1,还是方案2,发送端把消息成功中放去了队列,但消费端消费失败缘何办?

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

         基于以上分析,亲戚亲戚村里人 知道,你这些方案虽然是错误的!

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

但你这些方案的十个 多缺点某些:需要设计DB消息表,并肩还需要十个 多后台任务,不断扫描本地消息。原因分析分析 消息的正确处理和业务逻辑耦合额外增加业务方的负担。

通过底下3步,亲戚亲戚村里人 基本就正确处理了这里update db和发送网络消息这十个 多操作的原子性问题。

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

(1) 发送Prepared消息 

(2) update DB 

(3) 根据update DB结果成功或失败,Confirm机会注销Prepared消息。

消费成功,但insert判重表失败,缘何办?关于你这些,在Kafka的源码分析系列,第1篇, exactly once问题的以前,有过讨论。

你这些方案看似正确,虽然是错误的,原因分析分析 有2:

那你这些问题缘何正确处理呢?

(2)准备十个 多后台线程池池运行,源源不断的把消息表中的message传送给消息底下件。失败了,不断重试重传。允许消息重复,但消息不需要丢,顺序某些会打乱。