“得益于MQ削峰填谷,系统解耦,操作异步等功能特性,在互联网行业,可以说有分布式服务的地方,MQ都往往不会缺席。”

由阿里自研的RocketMQ更是经历了多年的双十一高并发挑战,其中4.3.0版本推出了事务消息的新特性本文对RocketMQ 4.5.0版本事务消息相关的源码跟踪介绍,通过阅读可以知道:

  • 事务消息解决什么样的问题

  • 事务消息的实现原理及其设计亮点


01——解决什么问题

假设我所在的系统现在有这样一个场景:

本地开启数据库事务进行扣款操作,成功后发送MQ消息给库存中心进行发货。

有人会想到开启mybatis事务实现,把本地事务和MQ消息放在一起不就行了吗?如果MQ发送成功,就提交事务,发送失败就回滚事务,整套操作一气呵成。


精简代码逻辑后可以清晰的看到

  • 开启一个线程来执行回查的逻辑

  • 执行transactionListener的checkLocalTransaction方法来获取本地事务执行的结果

RocketMQ Server

RocketMQ 服务器在收到Client发过来的Commit消息后会

读出半消息——>恢复topic等原消息体的信息——>和普通消息一样再次写入磁盘——>删除之前的半消息

如果是Rollback消息则直接删除之前的半消息

到此,:整条RocketMQ 事务消息的调用链就结束了

04——思考

1. 分布式事务等于事务消息吗?

两者并没有关系,事务消息仅仅保证本地事务和MQ消息发送形成整体的原子性,而投递到MQ服务器后,消费者是否能一定消费成功是无法保证的。

2. 源码设计上有什么亮点吗?

通过对整条链路源码的学习理解发现还是有不少亮点的

  • server端回查消息的发送,client端回查消息逻辑的处理,client端commit/rollback消息的提交都是用了异步进行,可以说能异步的地方都用了异步,通过异步+重试的方式保证了在分布式环境中即使短暂的网络状况不良好,也不会影响整体逻辑。

  • 引入TransactionListener,真正做到了开闭原则以及依赖倒置原则,面向接口编程。整体扩展性做得非常好,使用者只需要编写自己的Listener就可以做到事务消息的发送,非常方便

  • TransactionMQProducer通过继承DefaultMQProducer极大地复用了关于发送消息相关的逻辑

3. 源码设计上有什么不足吗?

RocketMQ作为一款极其成功的消息中间件,要发现不足不是那么容易了,笔者谈几点看法

  • sendMessageIntransaction等事务相关的方法被划分在了DefaultMQProducer里面,从内聚的角度来说这是跟事务相关的发送消息方法应该被划分在TransactionMQProducer。

  • 所有topic的半消息都会写在topic为RMQ_SYS_TRANS_OP_HALF_TOPIC的半消息队列里,并且每条半消息,在整个链路里会被写多次,如果并发很大且大部分消息都是事务消息的话,可靠性会存在问题。


  • 最后分享一份面试宝典【Java核心知识点整理】覆盖了JVM、锁、高并发、反射、Spring原理、微服务、Zookeeper、数据库、数据结构等等”,还有Java208道面试题(含答案)!

  • 加入我的粉丝群(Java填坑之路:659655594)即可免费获取到!掌握了这些知识点,面试时在候选人中又可以夺目不少,暴击9999点。机会都是留给有准备的人,只有充足的准备,才可能让自己可以在候选人中脱颖而出。