欢迎光临
我们一直在努力

RocketMQ延迟消息实现原理解析

一、核心原理概述

RocketMQ的延迟消息实现采用 "预置延迟等级 + 定时扫描转发" 的机制,并非真正的实时延迟,就是通过预定延迟等级将消息暂存到特定队列,等待时间到达后再投递给消费者。

1. 实现方式

RocketMQ 将延时消息转换为普通消息,通过 SCHEDULE_TOPIC_XXXX 主题进行分级存储和消费。

2. 延迟级别

RocketMQ 一共支持18个等级的延迟投递,具体时间如下:

投递等级(delay level)延迟时间投递等级(delay level)延迟时间
1 1s 10 6min
2 5s 11 7min
3 10s 12 8min
4 30s 13 9min
5 1min 14 10min
6 2min 15 20min
7 3min 16 30min
8 4min 17 1h
9 5min 18 2h

// RocketMQ预定义的18个延迟等级
private String messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h";
// 对应18个SCHEDULE_TOPIC_XXXX队列

3. 整体流程

二、核心实现步骤

发送阶段

java

// 生产者发送延迟消息
Message msg = new Message("TestTopic", "Hello RocketMQ".getBytes());
// 设置延迟级别(对应上面级别的索引,从1开始)
msg.setDelayTimeLevel(3); // 延迟10秒
producer.send(msg);

内部转换流程

  • 消息标记:Broker 收到延迟消息后,将原 Topic 和 QueueId 存入消息属性

  • 主题切换:将消息的实际 Topic 改为 SCHEDULE_TOPIC_XXXX

  • 队列分配:根据延迟级别分配到对应的延迟队列

    • 延迟级别1 → SCHEDULE_TOPIC_XXXX 的 Queue 0

    • 延迟级别2 → SCHEDULE_TOPIC_XXXX 的 Queue 1

    • 每个延迟级别对应一个专门的队列

  • 定时扫描机制

    java

    // 简化后的处理逻辑
    class ScheduleMessageService {
    // 定时任务,每秒执行一次 (实际会根据延迟级别进行分级延迟扫描)
    public void start() {
    for (int level = 1; level <= maxDelayLevel; level++) {
    // 计算当前级别对应的延迟时间
    long delayTime = computeDeliverTimestamp(level);
    // 扫描对应队列中到期的消息
    scanAndDeliver(level, delayTime);
    }
    }
    }

    消息投递

  • 扫描到期消息:每个延迟队列有独立的定时任务,按时间轮询扫描

  • 恢复原主题:从消息属性中取出原始 Topic 和 QueueId

  • 重新投递:将消息存入原始 Topic 的 CommitLog

  • 消费者消费:消费者从原始 Topic 正常消费消息

  • 三、 存储结构

    四、Broker核心处理流程

    五、 限制与改进

    配置延迟级别

    properties

    # broker.conf
    messageDelayLevel=1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h

    重要限制

  • 固定延迟级别:不支持任意时间延迟,只能使用预设级别

  • 时间精度:秒级精度

  • 最大延迟:默认最长2小时(可配置)

  • 消息顺序:延迟消息会破坏严格的消息顺序

  • 5.0+ 版本改进

    RocketMQ 5.0 引入了 TimerWheel(时间轮) 优化:

    • 支持任意时间延迟(毫秒级精度)

    • 更高的性能,O(1) 时间复杂度

    • 支持更长的延迟时间(数天级别)

     最佳实践

    java

    // 最佳实践
    public class DelayMessageExample {
    public void sendDelayMessage() {
    Message msg = new Message("OrderTopic", "订单超时取消".getBytes());

    // 根据业务需求选择合适的延迟级别
    // 订单超时:30分钟 → level 16
    // 支付提醒:15分钟 → 可选择10m或20m级别
    msg.setDelayTimeLevel(16); // 30分钟

    // 消息去重:延迟消息可能需要配合唯一Key
    msg.setKeys("ORDER_123456");

    producer.send(msg);
    }
    }

    总结

    RocketMQ 延迟消息通过 "主题转换 + 分级延迟队列 + 定时扫描" 实现,虽然不支持任意时间点延迟,但满足了大多数业务场景(如订单超时、定时提醒等)。对于更灵活的延迟需求,可考虑升级到 5.0+ 版本或使用时间轮实现。

    赞(0)
    未经允许不得转载:171主机测评 » RocketMQ延迟消息实现原理解析
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址