RocketMQ 定时消息和重试消息

本文详细解读了RocketMQ4.2.0版本中关于定时消息的设置、存储、预处理以及重试策略,包括定时级别、延迟时间和消费失败后的重试流程。

基于 RocketMQ 4.2.0 版本进行的源码分析。
讲述 RocketMQ 定时消息和重试消息

一、定时消息概述

RocketMQ 支持 Producer 端发送定时消息,即该消息被发送之后,到一段时间之后才能被 Consumer 消费者端消费。但是当前开源版本的 RocketMQ 所支持的定时时间是有限的、不同级别的精度的时间,并不是任意无限制的定时时间。因此在每条消息上设置定时时间的 API 叫做 setDelayTimeLevel,而非 setDelayTime 这样的命名:

Message msg =
    new Message("TopicTest" /* Topic */,
                "TagA" /* Tag */,
                ("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET) /* Message body */);
msg.setDelayTimeLevel(i + 1);

默认 Broker 服务器端有 18 个定时级别:

public class MessageStoreConfig {

    private String messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h";
    
}

这 18 个定时级别在服务器端启动的时候,会被解析并放置到表 delayLevelTable 中。解析的过程就是上述字符串按照空格拆分开,然后根据时间单位的不同再进一步进行计算,得到最终的毫秒时间。级别就是根据这些毫秒时间的顺序而确定的,例如上述 1s 延迟就是级别 1, 5s 延迟就是级别 2,以此类推:

public class ScheduleMessageService extends ConfigManager {

    public boolean parseDelayLevel() {
        for (int i = 0; i < levelArray.length; i++) {
            // ...
                
            int level = i + 1;
            long delayTimeMillis = tu * num;

            // 级别:延迟时间
            this.delayLevelTable.put(level, delayTimeMillis);
        }
    }
    
}

二、定时消息预存储

客户端在为某条消息设置上定时级别的时候,实际上级别这个字段会被作为附属属性放到消息中:

public class Message implements Serializable {

    public void setDelayTimeLevel(int level) {
        this.putProperty(MessageConst.PROPERTY_DELAY_TIME_LEVEL, String.valueOf(level));
    }
    
}

我们先前的文章提到过,发送到 Broker 服务器的消息会被存储到 CommitLog 消息文件中。那么在此处即使是定时消息也不例外,将定时消息存储下来是为了保证消息最大程度地不丢失。然而毕竟和普通消息不同,在遇到定时消息后,CommitLog 会将这条消息的话题和队列 ID 替换成专门用于定时的话题和相应的级别对应的队列 ID。真实的话题和队列 ID 会作为属性放置到这条消息中。

public class CommitLog {

    public PutMessageResult putMessage(final MessageExtBrokerInner msg) {

        // Delay Delivery
        if (msg.getDelayTimeLevel() > 0) {

            topic = ScheduleMessageService.SCHEDULE_TOPIC;
            queueId = ScheduleMessageService.delayLevel2QueueId(msg.getDelayTimeLevel());

            // Backup real topic, queueId
            MessageAccessor.putProperty(msg, MessageConst.PROPERTY_REAL_TOPIC, msg.getTopic());
            MessageAccessor.putProperty(msg, MessageConst.PROPERTY_REAL_QUEUE_ID, String.valueOf(msg.getQueueId()));
            msg.setPropertiesString(MessageDecoder.messageProperties2String(msg.getProperties()));

            // 替换 Topic 和 QueueID
            msg.setTopic(topic);
            msg.setQueueId(queueId);
        }
        
    }
    
}
</
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值