half 消息是如何对消费者不可见的?
其本质原因就是RocketMQ一旦发现你发送的是一个half消息,他不会把这个half消息的offset写入
OrderPaySuccessTopic
的ConsumeQueue
里去。他会把这条half消息写入到自己内部的“
RMQ_SYS_TRANS_HALF_TOPIC
”这个Topic对应的一个ConsumeQueue
里去事务消息机制之下的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如果执行rollback操作的话,如何标记消息回滚?
假设我们的订单系统执行了rollback请求,那么此时就需要对消息进行回滚。
之前我们说,RocketMQ会把这个half消息给删除,但是大家觉得删除消息是真的会在磁盘文件里删除吗?不是的
因为RocketMQ都是顺序把消息写入磁盘文件的,所以在这里如果你执行rollback,他的本质就是用一个OP操作来标记half消息的状态
RocketMQ内部有一个
OP_TOPIC
,此时可以写一条rollback OP
记录到这个Topic里,标记某个half
消息是rollback了,如下图。假设你一直没有执行commit/rollback,RocketMQ会回调订单系统的接口去判断half消息的状态,但是他最多就是回调15次,如果15次之后你都没法告知他half消息的状态,就自动把消息标记为rollback。
如果执行commit操作,如何让消息对红包系统可见?
如果订单系统执行了commit操作,如何让消息对红包系统可见呢?
其实也很简单,你执行commit操作之后,RocketMQ就会在
OP_TOPIC
里写入一条记录,标记half消息已经是commit
状态了。接着需要把放在
RMQ_SYS_TRANS_HALF_TOPIC
中的half消息给写入到OrderPaySuccessTopic
的ConsumeQueue里去,然后我们的红包系统可以就可以看到这条消息进行消费了,如下图。事务消息机制的本质都是基于
CommitLog
、ConsumeQueue
这套存储机制来做的,只不过中间有一些Topic
的变换,half消息可能就是写入内部Topic的。事务消息的缺点
事务消息复杂的机制完全有可能导致整体性能比较差,而且吞吐量比较低