延时队列
在实际业务场景中可能会用到延时消息发送,例如支付场景,准时支付、超过未支付将执行不同的方案,其中超时未支付可以看做一个延时消息。
延时队列的使用场景:
1.订单业务:在电商中,用户下单后30分钟后未付款则取消订单。
2.短信通知:用户下单并付款后,1分钟后发短信给用户。
最常用到方式为定时任务轮训,数据量小的时候使用没什么问题
而当有千万甚至上亿的数据量时就会出现数据读取的瓶颈,此时全表扫面进行处理一定是下下策。但是也有比较讨巧的方式。
本文会讲另一种方式即RabbitMQ延迟队列。RabbitMQ实际并没有直接实现延时队列,因为RabbitMQ本身不具有延时消息队列的功能,但可利用RabbitMQ提供的属性,通过TTL(Time
To Live)、DLX(Dead Letter
Exchanges)特性来模拟延时队列,其原理给消息设置过期时间,在消息队列上为过期消息指定转发器,这样消息过期后会转发到与指定转发器匹配的队列上,变向实现延时队列,
除了使用TTL、DLX实现的延时队列,也可以使用插件来实现。本文会介绍的使用使用插件rabbitmq_delayed_message_exchange来实现延时队列。
RabbitMQ延时队列逻辑:
单个延迟队列:
软件准备
erlang
请参考Win10下安装erlang
下载地址:
http://www.erlang.org/downloads
RabbitMQ
请参考win10下安装rabbitmq
下载地址:
http://www.rabbitmq.com/install-windows.html
rabbitmq_delayed_message_exchange插件
源码地址:
https://github.com/rabbitmq/rabbitmq-delayed-message-exchange
千万记住,一定选好版本号,RabbitMQ与插件rabbitmq_delayed_message_exchange插件要相匹配
下载完插件后,将其放置到RabbitMQ安装目录下的plugins目录下,并使用如下命令启动这个插件:
rabbitmq-plugins enable rabbitmq_delayed_message_exchange
启动插件成功后,记得重启一下RabbitMQ,让其生效。
SpringBoot整合RabbitMQ
- 在 pom.xml 中添加 spring-boot-starter-amqp的依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2. 接下来在application.yml文件中加入redis配置内容:
spring:
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
#手动ACK 不开启自动ACK模式,目的是防止报错后未正确处理消息丢失,默认为none
listener:
simple:
acknowledge-mode: manual
direct:
acknowledge-mode: manual
具体编码实现:
1.配置队列
package com.example.rabbitmq.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
/**
* 1.配置队列
*/
@Configuration
@Slf4j
public class DelayRabbitConfig {
/**
* 延迟队列TTL名称
*/
private static final String ORDER_DELAY_QUEUE = "order.delay.queue";
/**
* 交换机
*/
public static final String ORDER_DELAY_EXCHANGE = "order.delay.exchange";
/**
* routing key 名称
* 具体消息发送在该 routingKey 的
*/
public static final String ORDER_DELAY_ROUTING_KEY = "order_delay";
public static final String ORDER_QUEUE_NAME = "order.queue";
public static final String ORDER_EXCHANGE_NAME = "order.exchange";
public static final String ORDER_ROUTING_KEY = "order";
@Bean
public Queue delayOrderQueue() {
Map<String, Object> params = new HashMap<>(