消息产生后,生产者希望在间隔一段时间后被消费的场景可以使用定时消息,RocketMQ目前不支持自定义延迟时间,但可以指定延迟等级,可以选择18个延迟等级,分别是对应延迟时间是1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h。
RocketMQ的延迟消息主题是SCHEDULE_TOPIC_XXXX,18个延迟级别对应18个消息队列,当消息投递到broker后,如果消息中指定了延迟等级(DelayTimeLevel),消息topic会更改为SCHEDULE_TOPIC_XXXX,queueId更改为延迟等级对应的消息队列,原有的topic和queueId会放到msg属性的REAL_TOPIC与REAL_QID中。
延迟消息的处理由后台线程(ScheduleMessageService类)完成,RocketMQ使用的是java自带Timer类。延迟线程启动后为每个延迟等级创建一个延迟任务,运行后,按照延迟时间先后,选出最先要执行的任务,任务拿到执行权限后会便利对应的消息队列中的消息,如果已到执行时间则将消息重新写入commitlog,topic和queueId对应真实的主题和队列。如果消息还未到执行时间,计算延迟时间后,创建新的延迟任务放到timer中等待调度。
有延迟处理的原理可知,消息的延迟时间并不是精准的,每条消息被调度到依赖与前面消息的处理时常,如果需要处理的消息过多,就会延长后续消息被调度的时间,因此也就增加了延迟时间。因此如果需要精准的延迟时间,还需另外想办法。