half消息是如何对消费者不可见的
我们之前都分析过,我们发送一条消息到MQ时,会先创建一个topic,假设这个topic叫OrderPaySuccessTopic,然后把消息发送到这个topic中,然后通过MQ内部的流程,流入到某个broker的MessageQueue中,然后完整的数据信息写入commitLog中,把offset偏移量信息写入ConsumeQueue中,然后消费者订阅这个topic,就可以消费消息,但是当我们发送half消息的时候,为什么消费者就消费不到呢;其本质的一个原因就是RocketMQ一旦发现你发送的是一条half消息,它不会把这个half消息的offset写入OrderPaySuccessTopic中的ConsumeQueue里去,它会把这条half消息写入到自己内部的一个“RMQ_SYS_TRANS_HALF_TOPIC”这个topic对应的一个ConsumeQueue里去。(也就是说,消息的完整信息还是写入到commitlog中了,只是offset偏移量没有写到对应topic的consumeQueue中,而是写入到了MQ内部特定topic的consumeQueue文件中了)所以这就真相大白了,就能明白为什么消费者消费不到这条half消息了。
在什么情况下订单系统会接收到half消息写入成功的响应呢
就是必须要half消息进入到RocketMQ内部的RMQ_SYS_TRANS_HALF_TOPIC的comsumeQueue文件中,此时就认为half消息写入成功了,然后就会返回成功消息给订单系统了。
假设由于各种原因,MQ没有接受到rollback或commit消息,那MQ的消息处理方式是如何实现的
其实RocketMQ后台有个定时任务,它会定时的去扫描RMQ_SYS_TRANS_HALF_TOPIC中的half消息,如果超过一定的时间,还是half消息,那么它会回调订单系统提供的接口,问你这个消息是rollback呢,还是commit呢。
如果执行rollback,那如何标记消息回滚呢
之前我们说执行rollback请求后,MQ会删除这个half消息,你觉的MQ会真的删除该消息么?答案是不会真的删除的,因为RocketMQ都是顺序将消息写入磁盘文件的,所以在这里如果你执行rollback请求,它的本质是用一个op操作标记half消息的状态,这个op操作,就是RocketMQ中有一个OP_TOPIC,此时可以写一条rollback op记录到这个topic里,标记某个balf消息是被rollback了。
注:如果没有一直没有接受到rollback/commit请求,那么mq会主动调订单系统的接口,来询问这个half消息是需要rollback还是commit,这个最多回调15次,如果15次还没有一个准确的状态,那么mq自己就会把这个消息标记为rollback。
如果执行commit请求,如何让消费者系统看到呢
其实也很简单,如果订单系统执行了commit操作后,RocketMQ就会在OP_TOPIC中标记这个half消息为commit状态了。然后接着就需要将RMQ_SYS_TRANS_HALF_TOPIC中的half消息写入到OrderPaySuccessTopic的consumeQueue里去,然后我们的消费者系统,也就是积分系统就可以读取到这条消息了。