By source tell you, Ali RocketMQ transaction messages in the end regressed in which

"Thanks MQ load shifting, decoupling, asynchronous operation and other features in the Internet industry can be said to have a place to distributed services, MQ will often not be absent."

Ali from the Institute of RocketMQ more experienced double eleven years of high concurrency challenges, which launched the 4.3.0 version of the new features affairs news paper RocketMQ 4.5.0 version of the source code related to transaction message tracking reports, can know through reading :

  • Transaction message to solve any kind of problem

  • The principle of its design highlights transaction message


01-- solve any problems

I assume that the system where there is now such a scenario:

Local open-debit transaction database, MQ message sent after a successful delivery to the Stock Center.

Some people may think of open mybatis transaction implementation, the local transaction and MQ messaging together not on line yet? If MQ sent successfully, it commits the transaction, sending failed to roll back the transaction, the entire operation at one go.

By source tell you, Ali RocketMQ transaction messages in the end regressed in which


Seemingly no problem, but the network is not reliable in.

MQ return assumptions over the response because the network has yet to receive a reason, so I had to be rolled back in the face of an uncertain return MQ results. But MQ server has indeed received this message, but to respond to the client is lost, so is the result of a failed charge, successful delivery.

By source tell you, Ali RocketMQ transaction messages in the end regressed in which


Since sending MQ messages and local affairs can not write together, how to ensure that overall demand has atomicity of it? The answer is that today we introduce the protagonist: the transaction message .

02-- Overview

By source tell you, Ali RocketMQ transaction messages in the end regressed in which


Overall RocketMQ transaction message is divided into two main lines

  1. Sending process timer task : sending half message (message half), performs a local transaction, transmits transaction execution result

  2. Check back flow of regular tasks : MQ server back to check local affairs, sent the results of the transaction

Therefore, this paper were also analyzed by two main lines of the source

03-- source code analysis

Semi message sending process

Local application (client)

在本地应用发送事务消息的核心类是TransactionMQProducer,该类通过继承DefaultMQProducer来复用大部分发送消息相关的逻辑,这个类的代码量非常少只有100来行,下面是这个类的sendMessageTransaction方法

By source tell you, Ali RocketMQ transaction messages in the end regressed in which


这个方法做了两件事,

  1. 检查transactionListener是否存在

  2. 调用父类执行事务消息发送

TransactionListener在事务消息流程中起到至关重要的作用,一起看看这个接口

By source tell you, Ali RocketMQ transaction messages in the end regressed in which


接口注释说的很明白,配合上面的概览图来看就是,executeLocalTransaction方法对应的就是执行本地事务操作,checkLocalTransaction对应的就是回查本地事务操作。

下面是DefaultMQProducer类的

sendMessageInTransaction方法源码

By source tell you, Ali RocketMQ transaction messages in the end regressed in which


为了使源码的逻辑更加直观,笔者精简了核心代码。sendMessageInTransaction方法主要做了以下事情

  1. 给消息打上事务消息相关的标记,用于MQ服务端区分普通消息和事务消息

  2. 发送半消息(half message)

  3. 发送成功则由transactionListener执行本地事务

  4. 执行endTransaction方法,如果半消息发送失败本地事务执行失败告诉服务端是删除半消息,半消息发送成功本地事务执行成功则告诉服务端生效半消息。

发送半消息流程,Client端代码到这里差不多就结束了,接下来看看RocketMQ Server端是如何处理的

RocketMQ Server

Server在接收到消息过后会进行一些领域对象的转化和是否支持事务消息的权限校验,对理解事务消息用处不大,此处就省略对旁枝末节的介绍了。下面是TransactionalMessageBridge类处理half message的源码

By source tell you, Ali RocketMQ transaction messages in the end regressed in which


这两个方法主要做了以下事情:

By source tell you, Ali RocketMQ transaction messages in the end regressed in which


  1. 将消息的topic,queueId放进消息体自身的map里进行缓存

  2. 将消息的topic设置为“RMQ_SYS_TRANS_OP_HALF_TOPIC”,将queueId设置为0

  3. 将消息写入磁盘持久化

可以看到所有的事务半消息都会被放进同一个topic的同一个queue里面,通过对topic的区分,从而避免了半消息被consumer给消费到

Server将半消息持久化后然后会发送结果给我们本地的应用程序。到了这里Server端对半消息的处理就结束了,紧接着的是定时任务的登场。

定时任务回查流程

RocketMQ Server

定时任务是一个叫TransactionalMessageService类的线程,下面是该类的check方法

By source tell you, Ali RocketMQ transaction messages in the end regressed in which


check方法非常长,省略的代码大致都是对半消息进行过滤操作(如超过72小时的事务消息,就被算作过期),只保留符合条件的半消息对其进行回查。

其中很有意思的是putBackHalfMsgQueue方法,因为每次把半消息从磁盘拉到内存里进行处理都会对其属性进行改变(例如TRANSACTION_CHECK_TIMES,这是是否丢弃事务消息的关键信息)。

所以在发送回查消息之前需要对半消息再次放进磁盘。

RocketMQ采取的方法是基于最新的物理偏移量重新写入,而不是对原有的半消息进行修改,其中的目的就是RocketMQ的存储设计采用顺序写,如果去修改消息 ,无法做到高性能。

下面是resolveHalfMsg方法,主要就是开启一个线程然后发送check消息。

By source tell you, Ali RocketMQ transaction messages in the end regressed in which


本地应用(client)

下面是DefaultMQProducerImpl的checkTransactionState方法,是本地应用对回查消息的处理逻辑

By source tell you, Ali RocketMQ transaction messages in the end regressed in which


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

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

  • 执行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 other transaction related methods are divided DefaultMQProducer the inside, from the perspective of cohesive, this is sent with the message transaction related methods should be divided TransactionMQProducer.

  • All semi-topic messages are written on the topic for the message queue RMQ_SYS_TRANS_OP_HALF_TOPIC half, and each half message, there will be a link in the entire written many times, if a concurrent large and most of the message, then the message is transactional, reliability there will be a problem.


Guess you like

Origin blog.51cto.com/14480698/2427417