参考资料
七、延迟队列
7.1 什么是延迟队列
正常的MQ应用场景中,我们希望消息可以快速稳定的传递。但是有一些场景中,希望在指定的延迟后再消费信息,比如订单支付场景(订单15部分内未支付则关闭订单)。
这类实现延迟任务的场景,就可以采用延迟队列来实现。
以下介绍一下其他的一些方法。
7.2 延迟队列的解决方案
7.2.1 定时任务
每隔n秒扫描一次数据库,查询数据库装为过期的订单进行处理。
实现方式
spring schedule、quartz、xxljob等
优点
简单,容易实现;
缺点
- 存在延迟(受定时器延迟时间限制
- 性能较差,每次扫描数据库,如果订单量交大,会给数据库造成较大压力。
7.2.2 被动取消
当用户主动查询订单时,判断订单是否超时,超时则取消
- 优点:服务器压力小
- 缺点:如果用户长时间不查询,则会造成统计异常;而且用户打开订单页面会变慢,严重的话会影响用户体验
7.2.3 JDK的延迟队列
DelayedQueue:无界阻塞队列,该队列只有在延迟期满后,才能从中获取元素。
优点
实现简单,任务的延迟低。
缺点
- 服务器重启宕机,数据会丢失
- 只适用于单机版
- 订单量大时,可能会造成内存不足:OOM
7.2.3 采用消息中间件(rabbitMQ
RabbitMQ 本身不支持延迟队列,可以使用 TTL 结合 DLX 的方式来实现消息的延迟投递(前面提到的死信队列)。.

把 DLX 跟某个队列绑定,到了指定时间,消息过期后,就会从 DLX 路由到这个队列,消费者可以从DLX的队列中取走消息。
7.2.3.1 适用专门优化后的死信队列实现延迟队列
在上面的mq方案中,存在两个不同的交换机,我们可以利用直连交换机的特性,将交换机优化成一个交换机,同时通过不同的routingKey指定普通队列和死信队列。

思路解释
- 生产者发送消息到交换机X,并指定ttl的key
- 消息被交换机传递到ttl队列中(指定了消息过期时间的队列
- 同时,ttl队列还指定的死信交换机DLX为自身的交换机X,但是指定的routingKey为死信队列的key
- 这样,当消息在ttl队列中到期后,这条消息就会被传递到死信队列中,提供给消费者
7.2.3.2 ⭐️实例代码
为了便于测试,将发送和接收写在同一个服务中
配置信息
@Configuration
public class DelayExchangeConfig {
public static String exchangeName = "order.ttl.exchange";
public static String orderQ = "order.ttl.queue";
public static String dlxQ = "order.dlx.queue";
@Bean
public DirectExchange delayedExchange(){
return ExchangeBuilder.directExchange(exchangeName).build();
}
@Bean
public Queue orderQueue(){
// 指定该队列的过期时间和死信队列
Map<String , Object> properties = new HashMap<>();
properties.put("x-message-ttl" , 15000);
properties.put("x-dead-letter-exchange" , exchangeName);
properties.put("x-dead-letter-routing-key" , "dead-letter")

本文介绍了如何在RabbitMQ中使用延迟队列处理延迟任务,包括定时任务、被动取消、JDK延迟队列以及利用rabbitmq_delayed_message_exchange插件的实例和解决不同消息延迟时间的问题。
3152

被折叠的 条评论
为什么被折叠?



