大白话-设计RocketMQ延迟消息
延迟消息
一般用于:提前发送消息,延迟一段时间后才需要被处理的场景。比如:下单半小时后还未支付,则取消订单 释放库存 等。
RocketMQ的延迟消息使用上非常便捷,但是不支持任意时间的延迟,这一点对于有强迫症的朋友来说就比较难受,但是搞明白为什么这么设计后,就自然释怀了。
为什么RocketMQ不支持任意时间的延时?为什么延迟时间只能是从1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
这些时间段里选?如果让你来设计RocketMQ的延迟消息,你会怎么设计?本文从以上几个问题聊聊RocketMQ的延迟消息。
1、使用延迟消息
- 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);
2、延迟消息的原理
2.1、你会怎么设计
如果让你来设计RocketMQ的延迟消息,你会怎么设计?笔者会这样设计:
- 延迟消息也是个消息,只是多了延迟时间,既然是消息,不管是不是要立刻处理,先找个
临时Topic
存储起来。 - Topic里面实际上是一个个队列,那所有的延迟消息要存在一个队列里吗?
不要放在同一个队列里
,因为消息各自都有不同的延迟时间,如果放在一个队列里,会牵扯到其余问题:比如排序、比如记录消费位置等。所以是按延迟时间分开存。 - 消息已经存起来了,那怎么处理呢?既然涉及到了延迟时间,那自然启动线程去定时获取消息,判断消息的延迟时间是否已经到达,到达之后则取出来投放到
目的Topic
。
2.2、粗略架构图
讲到这里,延迟消息的***架构图基本浮现***出来了:
2.3、RocketMQ的设计
实际上RocketMQ在设计延迟消息时,跟上面的思路基本类似,不在赘述,额外补充几点:
- 消息进入Broker后,会被存储在Topic
SCHEDULE_TOPIC_XXXX
中,只是在Dashboard中看不到。 - Topic
SCHEDULE_TOPIC_XXXX
中有18个消息队列,分别存储18个延迟等级对应的消息。 - RocketMQ 在启动时,会从
broker.conf
中获取18个等级对应的时间,延迟等级和时间的关系会存在放到DelayLevelTable中。 - RocketMQ会开启18个定时任务每隔
100ms
,从TopicSCHEDULE_TOPIC_XXXX
判断18个队列里的第一个消息是否可以被投放,如果可以投放,则在投放到原本的目的Topic。判断逻辑:存入时间
+延迟时间
>当前时间
。
3、为什么不支持自定义延时时间
说到这里,估计你也能猜到,为什么不支持自定义延迟时间了,核心原因还是性能问题。
试想一下,如果设计成任意时间,那么就不可能使用18个队列了,更不可能使用无限个队列了,只可能使用单个队列。
但是如果使用单个队列,按照先进先出
的存放的话,那出现需要后进先出
的消息怎么办?那只能对整个队列进行排序,如果消息量很大,每次有消息进来都需要排序,那CPU肯定会被玩爆
。
而且队列里的消息被消费后,都会记录偏移量,如果每次有消息进来都要排序,那偏移量
则失去意义,增加了消息丢失的风险。
所以,RocketMQ的这种18个延迟时间等级的设计,虽然在延迟时间的自由度上作出了妥协
,但是基本满足业务,性能也很优秀。
4、总结
本文聊了RocketMQ延迟消息的使用、原理、解答了部分疑问。核心概念: 临时Topic 、 目的Topic 、 定时任务 、 18个延迟等级 、 18个消息队列 。RocketMQ延迟消息的设计方式,是一种兼顾了性能 和 业务的优秀设计。
本篇完结!感谢你的阅读,欢迎点赞 关注 收藏 私信!!!