在 RocketMQ 4.x 版本,使用延时消息来实现消息的定时消费。延时消息可以一定程度上实现定时发送,但是有一些局限。
RocketMQ 新版本基于时间轮算法引入了定时消息,目前,精确到秒级的定时消息实现的 pr 已经提交到社区,今天来介绍一下。
1 延时消息
1.1 简介
RocketMQ 的延时消息是指 Producer 发送消息后,Consumer 不会立即消费,而是需要等待固定的时间才能消费。在一些场景下,延时消息是很有用的,比如电商场景下关闭 30 分钟内未支付的订单。
使用延时消息非常简单,只需要给消息的 delayTimeLevel 属性赋值就可以。参考下面代码:
Message message = new Message("TestTopic", ("Hello scheduled message " + i).getBytes());
//第 3 个级别,10s
message.setDelayTimeLevel(3);
producer.send(message);
延时消息有 18 个级别,如下:
private String messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h";
1.2 实现原理
延时消息的实现原理如下图:
Producer 把消息发送到 Broker 后,Broker 判断到是延时消息,首先会把消息投递到延时队列(Topic = SCHEDULE_TOPIC_XXXX,queueId = delayTimeLevel - 1)。定时任务线程池会有 18 个线程来对延时队列进行调度,每个线程调度一个延时级别,调度任务把延时消息再投递到原始队列,这样 Consumer 就可以拉取到了。
1.3 存在不足
延时消息存在着一些不足:
1.延时级别只有 18 个,并不能满足所有场景;
2.如果通过修改 messageDelayLevel 配置来自定义延时级别,并不灵活,比如一个在大规模的平台上,延时级别成百上千,而且随时可能增加新的延时时间;
3.延时时间不准确,后台的定时线程可能会因为处理消息量大导致延时误差大。
2 定时消息
为了弥补延时消息的不足,RocketMQ 5.0 引入了定时消息。