分布式事务?来看RocketMQ是如何解决的!

RocketMQ是如何实现事务消息的?

驾长车,踏破贺兰山缺。

哈喽大家好呀,我是际遇,RocketMQ相关的文章也差不多快要写完了,最后还剩一点点结尾的东西,这一篇就再跟大家聊一聊RocketMQ的事务消息吧。


面试官:又是你呀小伙子,今天咱们继续?你跟我说说你对事务的了解吧。

事务消息的使用场景

额,是这样的面试官,首先呢,还是要先说一下什么是事务的,最简单的例子呢,都已经是老生常谈了,比如银行转账对吧?

某天呢,我收到一个消息,陈冠希告诉我要我给他微信转账300块,帮他回香港,那我肯定马上就转了呀。那这里是如何保证我的账户扣钱后,陈冠希的账户加钱的呢?此类的问题都可以归结为事务问题。

我们可以简单的理解为一个表更新成功后如何保证另一个表更新成功,对吧。那我们很简单的可以用本地事务来解决,且Spring的@Transactional注解就可以很简单的解决这个问题。

面试官:实际的场景可以并没有如此简单,如果是大型的互联网应用,系统规模当然也不会小,会存在许多的数据库实例,分库,分表等等。那我们修改的表往往不在同一个实例中,那这个时候本地事务还生效吗?

嗯,你说的很对,在这种情况下,我们就要考虑分布式事务来解决这一类的问题了,而上次我们聊的RocketMQ的一大特点就是支持分布式事务消息,支持一些分布式事务的场景,所以在这个情况下,我们就可以考虑使用RocketMQ来作为解决方案。

哦?那既然你提到了RocketMQ的分布式事务,那你就说说看它是如何实现的吧。

内心OS:这不又是上钩了吗?分布式事务不会,RocketMQ我可以轻松拿捏呀,还想搞我分布式事务?

如何发送和消费事务消息

好的面试官,首先呢,RocketMQ可以通过发送事务消息来实现上面的场景。

  • 首先呢,Order对象包含了一个简单的订单信息,随机生成了一个ID作为事务的ID,定义了一个名为OrderTransactionGroup的事务组,用于下一步的接受本地事务的监听,这个时候其实消息已经发送到了Broker中,但并没有投递出去,消费者暂时还没办法消费这条消息。
  • 然后我们开始执行订单入库的事务操作,提交事务或者回滚事务消息。

    • 这里要说一下RocketMQLocalTransactionListener接口,使用@RocketMQTransactionListener注解用于接受本地事务的监听。注解中的txProducerGroup是事务组名称,和前面定义的OrderTransactionGroup保持一致,而RocketMQLocalTransactionListener接口有两个实现方法:

      • executeLocalTransaction:执行本地事务,在第一个步骤,发送消息成功会回调执行,一旦事务被提交成功,下游的消费者就能接收到消息。
      • checkLocalTransaction:检查本地事务的执行状态,如果executeLocalTransaction方法中返回的状态是Unknown或者没有返回状态,那么,默认会在预处理发送的1分钟后由broker通知消息发送方检查本地事务,在消息发送方中回调本地事务监听器中的checkLocalTransaction方法。检查事务的时候,可以根据事务的ID查询本地事务的状态,再返回具体事务状态给Broker。
  • 那现在一切准备就绪,就可以消费订单消息了。消息事务消息与消费普通消息的代码是一致的,不用做任何修改。

小伙子我听懂了,那你能再跟我说一下RocketMQ的这种方案是采用的常见的那种分布式解决方案吗?又是什么实现原理呢?

内心OS:没完没了了是吧,合着到最后还是绕回来了。

事务消息的技术原理

嗯,是这样的面试官,RocketMQ呢,采用了2PC的方案来解决的,后续咱们有时间呢,也可详细聊一下其他的分布式事务解决方案,这个2PC的原理是这样的:

  • 第一阶段,Producer向Broker发送预处理消息,这种消息也被叫做半消息,此时消息还没有投递出去,Consumer不能消费。
  • 第二阶段,Producer向Broker发送提交或者回滚的消息,具体流程呢,我可以通过一个图来向您解释:
  • 如果本地事务执行失败,发送回滚请求来回滚事务消息,消息不会投递给Consumer。
  • 如果本地事务状态未知,或者因为网络故障其他原因宕机,Broker未收到二次确认消息。由Broker端发送请求给Producer进行消息回查,确认提交或者回滚请求。如果消息一直未被确认,则这个时候就需要人工介入处理。

小伙子底子不错呀,今天咱们就到这吧,既然你懂这么懂,那我们下次就再聊聊RocketMQ的高性能和高可用吧。

内心OS:老头你这是点我呢?唉,看来回去还得再加班看看RocketMQ的高性能和高可用设计了,这老头是真狠啊!

后记

写了这么多关于RocketMQ的,这篇算是最轻松的了,也是比较好掌握的,2PC的设计也是分布式事务的解决方案的一种,下次我准备专门写一篇关于TCC,2PC等这类分布式事务的解决方案的。

其实关于分布式事务,大家,包括我身边的同时都有很多不同的看法,有的人说,面试造火箭,工作拧螺丝,这些分布式事务,小厂问得最多,而用起来的,微乎其微,而且入职之后碰到它的概率几乎为0。与其花时间在这上面,不如多花点时间做做自己的本地项目,刷刷算法。

对于以上这一类的想法呢,现在的我是不认同的,我认为,如果我们花时间去看这类的解决方案,是为了面试,为了背下来应付面试官(当然,文章的风格不代表我自己真实的目的哈哈哈哈),那大可不必,源码都没必要去读。但我们在看这些我们或许摸不到的解决方案的时候,能够培养我们解决问题的思维,思考的方式,这个是最重要的,对吧!

相信大家也有关注一些跟自己没那么相关的事务,比如,比如哈,国际局势,那我们关注这些又是为了什么呢?

为了有跟人聊天的谈资?

还是为了有自己对整件事情的思考呢?

相关推荐
曹牧24 分钟前
文档格式:OFD
java
豆角焖肉1 小时前
Maven进阶与搭建私服
java·maven
大不点wow1 小时前
Java序列化与反序列化:让对象走出JVM
java·开发语言·jvm
止语Lab1 小时前
好的 DX 不等于少写代码——三种语言的摩擦力设计课
后端
吃饱了得干活1 小时前
别再手动解析 LLM 输出了!LangChain 四种结构化输出方案对比
后端·python·langchain
噢,我明白了1 小时前
Java中日期和字符串的处理
java·开发语言·日期
程序员天天困1 小时前
Arthas trace 命令怎么用?一行定位最慢那行代码
jvm·后端
Huiturn1 小时前
GPT 5.6 连续编码 10 小时,纯 Python 啃下 Word 二进制格式——doc2docx 实现拆解
后端
dkbnull1 小时前
Spring Boot请求处理组件对比详解
java·spring boot
jun_bai1 小时前
Orthanc服务器使用java上传dicom影像文件
java·运维·服务器