事务消息机制的底层实现原理

half 消息是如何对消费者不可见的?

其本质原因就是RocketMQ一旦发现你发送的是一个half消息,他不会把这个half消息的offset写入OrderPaySuccessTopicConsumeQueue里去。
他会把这条half消息写入到自己内部的“RMQ_SYS_TRANS_HALF_TOPIC”这个Topic对应的一个ConsumeQueue里去
notion image
事务消息机制之下的half消息,RocketMQ是写入内部Topic的ConsumeQueue的,不是写入你指定的OrderPaySuccessTopic的ConsumeQueue的
所以你的红包系统自然无法从OrderPaySuccessTopic的ConsumeQueue中看到这条half消息了

在什么情况下订单系统会收到half消息成功的响应?

必须要half消息进入到RocketMQ内部的RMQ_SYS_TRANS_HALF_TOPIC的ConsumeQueue文件了,此时就会认为half消息写入成功了,然后就会返回响应给订单系统。
所以这个时候,一旦你的订单系统收到这个half消息写入成功的响应,必然就知道这个half消息已经在RocketMQ内部了。

假如因为各种问题,没有执行rollback或者commit会怎么样

其实这个时候他会在后台有定时任务,定时任务会去扫描RMQ_SYS_TRANS_HALF_TOPIC中的half消息,如果你超过一定时间还是half消息,他会回调订单系统的接口,让你判断这个half消息是要rollback还是commit
notion image

如果执行rollback操作的话,如何标记消息回滚?

假设我们的订单系统执行了rollback请求,那么此时就需要对消息进行回滚。
之前我们说,RocketMQ会把这个half消息给删除,但是大家觉得删除消息是真的会在磁盘文件里删除吗?不是的
因为RocketMQ都是顺序把消息写入磁盘文件的,所以在这里如果你执行rollback,他的本质就是用一个OP操作来标记half消息的状态
RocketMQ内部有一个OP_TOPIC,此时可以写一条rollback OP记录到这个Topic里,标记某个half消息是rollback了,如下图。
notion image
假设你一直没有执行commit/rollback,RocketMQ会回调订单系统的接口去判断half消息的状态,但是他最多就是回调15次,如果15次之后你都没法告知他half消息的状态,就自动把消息标记为rollback。

如果执行commit操作,如何让消息对红包系统可见?

如果订单系统执行了commit操作,如何让消息对红包系统可见呢?
其实也很简单,你执行commit操作之后,RocketMQ就会在OP_TOPIC里写入一条记录,标记half消息已经是commit状态了。
接着需要把放在RMQ_SYS_TRANS_HALF_TOPIC中的half消息给写入到OrderPaySuccessTopic的ConsumeQueue里去,然后我们的红包系统可以就可以看到这条消息进行消费了,如下图。
notion image
事务消息机制的本质都是基于CommitLogConsumeQueue这套存储机制来做的,只不过中间有一些Topic的变换,half消息可能就是写入内部Topic的。
 

事务消息的缺点

事务消息复杂的机制完全有可能导致整体性能比较差,而且吞吐量比较低