大白话设计RocketMQ延迟消息

开发
RocketMQ延迟消息的设计方式,是一种兼顾了性能和业务的优秀设计。本文聊了RocketMQ延迟消息的使用、原理、解答了部分疑问。

延迟消息一般用于:提前发送消息,延迟一段时间后才需要被处理的场景。比如:下单半小时后还未支付,则取消订单 释放库存 等。

RocketMQ的延迟消息使用上非常便捷,但是不支持任意时间的延迟,这一点对于有强迫症的朋友来说就比较难受,但是搞明白为什么这么设计后,就自然释怀了。

为什么RocketMQ不支持任意时间的延时?为什么延迟时间只能是从1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h这些时间段里选?如果让你来设计RocketMQ的延迟消息,你会怎么设计?本文从以上几个问题聊聊RocketMQ的延迟消息。

一、使用延迟消息

RocketMQ不支持任意时间的延迟,只有18个等级的延迟时间,默认是:1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h。从头到尾共18个等级时间,s、m、h、d,分别表示秒、分、时、天。

默认的18个等级对应的时间可以修改,在broker.conf中增加如下配置,根据自身需求修改时间,然后重启broker。

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

RocketMQ发送延迟消息只需要给消息设置延迟时间级别setDelayTimeLevel。

DefaultMQProducer producer = new DefaultMQProducer("TestProducerGroup");
Message rocketMsg = new Message(topic, tags, payloads);
// delayLevel=0时,无需延迟
if (delayLevel > 0) {
    rocketMsg.setDelayTimeLevel(delayLevel);
}
SendResult sendResult = producer.send(rocketMsg, timeout);

二、延迟消息的原理

1.你会怎么设计

如果让你来设计RocketMQ的延迟消息,你会怎么设计?笔者会这样设计:

  • 延迟消息也是个消息,只是多了延迟时间,既然是消息,不管是不是要立刻处理,先找个临时Topic存储起来。
  • Topic里面实际上是一个个队列,那所有的延迟消息要存在一个队列里吗?不要放在同一个队列里,因为消息各自都有不同的延迟时间,如果放在一个队列里,会牵扯到其余问题:比如排序、比如记录消费位置等。所以是按延迟时间分开存。
  • 消息已经存起来了,那怎么处理呢?既然涉及到了延迟时间,那自然启动线程去定时获取消息,判断消息的延迟时间是否已经到达,到达之后则取出来投放到目的Topic。

2.粗略架构图

讲到这里,延迟消息的架构图基本浮现出来了:

3.RocketMQ的设计

实际上RocketMQ在设计延迟消息时,跟上面的思路基本类似,不在赘述,额外补充几点:

  • 消息进入Broker后,会被存储在TopicSCHEDULE_TOPIC_XXXX中,只是在Dashboard中看不到。
  • TopicSCHEDULE_TOPIC_XXXX中有18个消息队列,分别存储18个延迟等级对应的消息。
  • RocketMQ 在启动时,会从broker.conf中获取18个等级对应的时间,延迟等级和时间的关系会存在放到DelayLevelTable中。
  • RocketMQ会开启18个定时任务每隔100ms,从TopicSCHEDULE_TOPIC_XXXX判断18个队列里的第一个消息是否可以被投放,如果可以投放,则在投放到原本的目的Topic。判断逻辑:存入时间+延迟时间 > 当前时间。

三、为什么不支持自定义延时时间

说到这里,估计你也能猜到,为什么不支持自定义延迟时间了,核心原因还是性能问题。

试想一下,如果设计成任意时间,那么就不可能使用18个队列了,更不可能使用无限个队列了,只可能使用单个队列。

但是如果使用单个队列,按照先进先出的存放的话,那出现需要后进先出的消息怎么办?那只能对整个队列进行排序,如果消息量很大,每次有消息进来都需要排序,那CPU肯定会被玩爆。

而且队列里的消息被消费后,都会记录偏移量,如果每次有消息进来都要排序,那偏移量则失去意义,增加了消息丢失的风险。

所以,RocketMQ的这种18个延迟时间等级的设计,虽然在延迟时间的自由度上作出了妥协,但是基本满足业务,性能也很优秀。

四、总结

本文聊了RocketMQ延迟消息的使用、原理、解答了部分疑问。核心概念:临时Topic、目的Topic、定时任务、18个延迟等级、18个消息队列。RocketMQ延迟消息的设计方式,是一种兼顾了性能和业务的优秀设计。

责任编辑:赵宁宁 来源: 不焦躁的程序员
相关推荐

2020-02-04 15:00:25

大白话认识JVM

2023-12-18 10:08:56

2023-12-27 13:54:00

RocketMQJava架构

2020-02-20 11:32:09

Kafka概念问题

2020-12-04 06:40:46

Zookeeper选举机制

2019-05-17 08:27:23

SQL注入漏洞攻击

2021-03-01 18:38:32

Mock测试软件

2021-02-18 09:06:39

数据访问者模式

2019-08-14 09:13:38

中台互联网业务

2024-04-24 12:41:10

Rust安全性内存

2020-11-13 16:40:05

RocketMQ延迟消息架构

2023-09-18 14:34:07

Kubernetes云原生

2021-01-27 13:50:17

AI 数据机器学习

2018-11-19 08:34:22

Hadoop架构HDFS

2020-09-08 06:30:59

微服务代码模块

2021-10-08 08:58:35

物联网通信发布者

2023-05-06 07:29:49

Spring事务传播

2023-09-13 09:02:22

PVPVC存储

2021-01-22 09:39:54

人工智能人工智能技术

2020-11-10 16:00:55

机器学习人工智能AI
点赞
收藏

51CTO技术栈公众号