RabbitMQ 使用插件实现延时队列
参考?:https://github.com/rabbitmq/rabbitmq-delayed-message-exchange
使用场景
- 订单下单30分钟后,如果用户没有付款,则系统自动取消订单。
- 会议开始前10分钟,推送消息提醒用户。
- 自定义某个操作的执行时间,如果设置文章在明早9点发布。
优势
-
替代轮询。
若数据库数据量大,则定时轮询就会特别消耗资源,拖垮服务器,且响应慢。
实现方案
rabbitmq有两种方式实现延时队列。(第一种方式在同级目录下,这篇文章只写第二种方式)
方案一:是通过设置队列的Dead Letter Exchanes和队列或消息的TTL。
方案二:是通过rabbitmq_delayed_message_exchange插件。
概要
- 新增type为x-delayed-message的exchange,必须配置x-delayed-type: topic/direct/fanout。
- 新增队列queue1, 绑定exchange和routingkey(rountingkey根据自己的需求来,可配可不配)。
- 生产者设置消息的delay时长并发送消息至queue1。
- 消费者消费queue1。
具体实现
引入maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
代码实现
@Test
public void sendToDeadQueue20() {
sendToDeadQueue(12);
sendToDeadQueue(30);
sendToDeadQueue(20);
sendToDeadQueue(15);
sendToDeadQueue(25);
sendToDeadQueue(14);
sendToDeadQueue(13);
sendToDeadQueue(16);
sendToDeadQueue(11);
sendToDeadQueue(10);
}
public void sendToDeadQueue(Integer expire) {
MessageProperties messageProperties = new MessageProperties();
messageProperties.setDelay(expire * 1000);
messageProperties.setContentType("json");
Message message = new Message(expire.toString().getBytes(), messageProperties);
amqpTemplate.convertAndSend("exchange", "rountingKey", message);
}
@RabbitListener(queues = "queue1")
public void calendarPopUp(byte[] msg) {
try {
String s = new String(msg, "UTF-8");
log.info(s);
} catch (Exception e) {
log.error("[{}]字符转换异常:", msg, e);
}
}
控制台输出
10
11
12
13
14
15
16
20
25
30
若delay延时时长已经过了,消费者依然会消费该消息。因为该插件实现的功能只是延时投递。经过了设置的delay时长,消息才会进入队列,并不在意消费者有无消费该队列。
该插件的影响和限制
- 会降低性能,所以如果没有该需求,则不要使用。
- 该插件不适合大数据量的延时消息,比如百万或一亿。
- 延时时长:0<=n<=(2^32)-1 ,单位毫秒。