RocketMQ学习(七)——RocketMQ延时消息

本文详细介绍了RocketMQ的延时消息机制,包括设置延时级别、producer发送、broker处理流程,以及延时消息与普通消息的区别。RocketMQ目前支持固定精度的延时消息,通过ScheduleMessageService定时处理延时队列中的消息,将它们重新发送到原始topic供consumer消费。
摘要由CSDN通过智能技术生成

用户发送的消息也可以指定延时时间(更准确的说是延时等级),然后在指定延时时间之后投递消息,然后被consumer消费。阿里云的ons还支持定时消息,而且延时消息是直接指定延时时间,其实阿里云的延时消息也是定时消息的另一种表述方式,都是通过设置消息被投递的时间来实现的,但是Apache RocketMQ在版本4.2.0中尚不支持指定时间的延时,只能通过配置延时等级和延时等级对应的时间来实现延时。

一个延时消息被发出到消费成功经历以下几个过程:
1) 设置消息的延时级别delayLevel。
2) producer发送消息。
3) broker收到消息在准备将消息写入存储的时候,判断是延时消息则更改Message的topic为延时消息队列的topic,也就是将消息投递到延时消息队列。
4) 有定时任务从延时队列中读取消息,拿到消息后判断是否达到延时时间,如果到了则修改topic为原始topic。并将消息投递到原始topic的队列。
5) consumer像消费其他消息一样从broker拉取消息进行消费。
注意: 批量消息是不支持延时消息的。

延时消息

消息的延时是在broker上操作的,消息发动Broker后,要特定的时间才会被Consumer消费。目前只支持固定精度的定时消息。消息到延时级别在Rocket源码中已经定义好,我们无法修改。

rocketmq-store 中到 MessageStoreConfig类

    private String messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h";
producer发送延时消息

在producer中发送消息的时候,设置Message的delayLevel。

// org.apache.rocketmq.common.message.Message
public void setDelayTimeLevel(int level) {
   
    this.putProperty(MessageConst.PROPERTY_DELAY_TIME_LEVEL, String.valueOf(level));
}

调用上面的方法设置延时等级的时候,会向message添加"DELAY"属性,后面broker处理延时消息就是依赖该属性进行特别的处理。接下来发送消息的流程和正常发送消息的流程基本一致,只是会将该消息标记为延时消息类型。

// org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl#sendKernelImpl 
if (msg.getProperty("__STARTDELIVERTIME") != null || msg.getProperty(MessageConst.PROPERTY_DELAY_TIME_LEVEL) != null) {
   
    context.setMsgType(MessageType.Delay_Msg);
}
broker处理延时消息

broker收到延时消息和正常消息在前置的处理流程是一致的,对于延时消息的特殊处理体现在将消息写入存储(内存或文件)的时候。

// org.apache.rocketmq.store.CommitLog#putMessage
public PutMessageResult putMessage(final MessageExtBrokerInner msg) {
   
    // 省略中间代码...
    StoreStatsService storeStatsService = this.defaultMessageStore.getStoreStatsService();

    // 拿到原始topic和对应的queueId
    String topic = msg.getTopic();
    int queueId = msg.getQueueId();

    final int tranType = MessageSysFlag.getTransactionValue(msg.getSysFlag());
    // 非事务消息和事务的commit消息才会进一步判断delayLevel
    if (tranType == MessageSysFlag.TRANSACTION_NOT_TYPE
        || tranType == MessageSysFlag.TRANSACTION_COMMIT_TYPE) {
   
        // Delay Delivery
        if (msg.getDelayTimeLevel() > 0) {
   
            // 纠正设置过大的level,就是delayLevel设置都大于延时时间等级的最大级
            if (msg.getDelayTimeLevel() > this.defaultMessageStore.getScheduleMessageService().getMaxDelayLevel()) {
   
                msg.setDelayTimeLevel(this.defaultMessageStore.getScheduleMessageService().getMaxDelayLevel());
            }

            // 设置为延时队列的topic
            topic = ScheduleMessageService.SCHEDULE_TOPIC;
            // 每一个延时等级一个queue,queueId = delayLevel - 1
            queueId = ScheduleMessageService.delayLevel2QueueId(msg.getDelayTimeLevel());

            // Backup real topic, queueId
            // 备份原始的topic和queueId
            MessageAccessor.putProperty(msg, MessageConst.PROPERTY_REAL_TOPIC, msg.getTopic()
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值