原文网址:RabbitMQ--延迟队列--使用/原理_IT利刃出鞘的博客-CSDN博客
简介
本文介绍RabbitMQ的延迟队列的用法。
本内容也是Java后端面试中常见的问题。
概述
延迟队列用来存放延迟消息。延迟消息:指当消息被发送以后,不想让消费者立刻拿到消息,而是等待特定时间后,消费者才能拿到这个消息进行消费。
在AMQP协议中,或者RabbitMQ本身没有直接支持延迟队列的功能,但是有两种方案来实现:
- 方案1:采用rabbitmq-delayed-message-exchange 插件实现。(RabbitMQ 3.6.x开始支持)
- 推荐。原因:它解决了死信队列的消息投递问题:在第一条消息成为死信之前,后面的消息即使过期也不会投递为死信。
- 方案2:通过前面所介绍的DLX和TTL模拟出延迟队列的功能。
- 不推荐。原因:死信队列的设计目的是为了存储没有被正常消费的消息,便于排查和重新投递。死信队列没有对投递时间做出保证,在第一条消息成为死信之前,后面的消息即使过期也不会投递为死信。
在图1-2中,不仅展示的是死信队列的用法,也是延迟队列的用法,对于queue.dlx这个死信队列来说,同样可以看作延迟队列。假设一个应用中需要将每条消息都设置为10秒的延迟,
生产者通过exchange.normal这个交换器将发送的消息存储在queue.normal这个队列中。消费者订阅的并非是queue.normal这个队列,而是queue.dlx这个队列。当消息从queue.normal这个队列中过期之后被存入queue.dlx这个队列中,消费者就恰巧消费到了延迟10秒的这条消息。
在真实应用中,对于延迟队列可以根据延迟时间的长短分为多个等级,一般分为5秒、10秒、30秒、1分钟、5分钟、10分钟、30分钟、1小时这几个维度,当然也可以再细化一下。
以下图(图2-1)为例进行说明。为简化,只设置5秒、10秒、30秒、1分钟这四个等级。根据需求的不同,生产者发送消息的时候通过设置不同的路由键,将消息发送到与交换器绑定的不同的队列中。这里队列也分别配置了DLX和相应的死信队列,当相应的消息过期时,就会转存到相应的死信队列(即延迟队列)中,这样消费者根据业务自身的情况,分别选择不同延迟等级的延迟队列进行消费。
使用场景
延迟队列的使用场景有很多,比如:
- 用户下订单场景:用户下单后有30分钟的时间支付,若30分钟内没有支付,则将这个订单取消。
- 方案:用户下单后将取消订单的消息发送到延迟队列,延迟时间设置为30分钟。取消订单这个消息的订阅者程序在30分钟后收到消息,判断该订单的状态是否为已支付,若还没支付,则将该订单状态设置为:已取消。
- 定时遥控场景:用户想用手机远程遥控家里的智能设备在指定的时间工作。
- 方案:假设用户想要的操作是:开启热水器。首先,将开启热水器这个消息发送到延迟队列,延迟时间设置到用户想要的时间到现在时间的差值。开启热水器这个消息的订阅者程序在指定时间收到消息,再将指令推送到智能设备。
需要注意的是,延迟队列的消息是不能取消的,解决方案是:在消费消息的时候判断这个消息对应的业务的当前状态。例如:对于取消订单来说,收到消息时,读取这个消息所对应的数据库信息,如果已经是已付款状态了,就不进行任何操作了,如果是未支付状态,则改为已取消。
其他网址
《RabbitMQ实战指南》=> 4.4 延迟队列