【消费】RocketMQ定时消息学习

RocketMQ支持定时消息,发送消息时可以选择18个延迟level中的一个level,延迟一段时间投递。这18个level分别为
1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
broker有配置项messageDelayLevel,默认值为“1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h”,18个level,可以配置s m h d四种级别
Version:4.5.0

消息发送

在消息中设置延迟级别的属性

message.setDelayTimeLevel(3);
SendResult result = producer.send(message);

发送端处理

在MQClientImpl.sendMessage中有一个RPC请求,RequestCode为310,Broker端对这个消息进行处理

Broker端处理

Broker在启动的时候会注册一系列processor,其中延迟消息用RequestCode.SendMessage_V2,如下:

/**
* SendMessageProcessor
*/
SendMessageProcessor sendProcessor = new SendMessageProcessor(this);
sendProcessor.registerSendMessageHook(sendMessageHookList);
sendProcessor.registerConsumeMessageHook(consumeMessageHookList);
this.remotingServer.registerProcessor(RequestCode.SEND_MESSAGE, sendProcessor, this.sendMessageExecutor);
// 延迟消息processor
this.remotingServer.registerProcessor(RequestCode.SEND_MESSAGE_V2, sendProcessor, this.sendMessageExecutor);
// 批量消息processor
this.remotingServer.registerProcessor(RequestCode.SEND_BATCH_MESSAGE, sendProcessor, this.sendMessageExecutor);
// 消费失败重发processor
this.remotingServer.registerProcessor(RequestCode.CONSUMER_SEND_MSG_BACK, sendProcessor, this.sendMessageExecutor);
this.fastRemotingServer.registerProcessor(RequestCode.SEND_MESSAGE, sendProcessor, this.sendMessageExecutor);
this.fastRemotingServer.registerProcessor(RequestCode.SEND_MESSAGE_V2, sendProcessor, this.sendMessageExecutor);
this.fastRemotingServer.registerProcessor(RequestCode.SEND_BATCH_MESSAGE, sendProcessor, this.sendMessageExecutor);
this.fastRemotingServer.registerProcessor(RequestCode.CONSUMER_SEND_MSG_BACK, sendProcessor, this.sendMessageExecutor);

进入这个Processor处理的过程看看,会按照正常的消息发送过程处理,核心方法在DefaultMessageStore.putMessage方法中,当处理消息的属性中存在DelayTimeLevel时,首先替换真实topic为SCHEDULE_TOPIC_XXXX,将queueid改成delayLevel - 1,然后将真实topic和queueId保存在消息属性中
CommitLog.putMessage()
image

接下来就是根据CommitLog生成ConsumeQueue的过程,由于之前将所有的延迟消息的topic统一了,并且不同延迟级别的消息的queueId不同,因此生成的ConsumeQueue也是不同,并且是和正常消息分开的。下图为ConsumeQueue的物理逻辑

由于consumeQueue后台会有一个线程ReputMessageService.doReput()不断地进行处理生成ConsumeQueue和IndexFile,这个过程不需要看。

发送阶段结束了,当消费者消费消息的时候,会根据ConsumeQueue这个索引在CommitLog中找到正确的消息,然后处理。

那么延迟消息到底是怎么判断什么时候该被消费呢?

ScheduleMessageService处理

Store启动时,调用ScheduleMessageService.start()
image

  1. 找到延迟级别对应的CQ
  2. 遍历CQ中的每一项
  3. 计算tagsCode
  4. 如果投递时间比当前时间小,立即投递,否则指定投递时间
  5. ScheduleMessageService.this.writeMessageStore.putMessage(msgInner) 投递消息
    image

tagcode作用是什么呢?
在调度消息的时候,定时消息的topic为SCHEDULE_TOPIC_XXXX,真实topic在属性中,所以来到消费的逻辑看

在进行消费的时候,通过比较tagCode直接判断这条消息是不是应该被投递

posted @   风卷红旗过大江  阅读(358)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示