延迟 队列

延迟队列应用场景:

  1. 定时发布文章
  2. 秒杀后给30分钟时间进行支付,如果30分钟后没有支付取消订单
  3. 预约餐厅提前30分钟通知

A -> 13:00 17:00 16:30 延迟时间: 7*30 * 60 * 1000

B -> 11:00 18:00 17:30 延迟时间: 13*30 * 60 * 1000

C -> 8:00 14:00 13:30 延迟时间: 11*30 * 60 * 1000

实现方案

第一种方式:创建具有超时功能且绑定死信交换机的消息队列
java 复制代码
   @Bean
    public Queue directQueueLong(){
        return   QueueBuilder.durable("业务队列名称")
                .deadLetterExchange("死信交换机名称")
                .deadLetterRoutingKey("死信队列 RoutingKey")
                .ttl(20000) // 消息停留时间
                //.maxLength(500)
                .build();
    }

监听死信队列,即可处理超时的消息队列

缺点:

上述实现方式中,ttl延时队列中所有的消息超时时间都是一样的,如果不同消息想设置不一样的超时时间,就需要建立多个不同超时时间的消息队列,比较麻烦,且不利于维护。

第二种方式:创建通用延时消息
java 复制代码
rabbitTemplate.convertAndSend("交换机名称", "RoutingKey","对象",message => {

message.getMessageProperties().setExpiration(String.valueOf(5000))
 return message;
}
  );

缺点:

该种方式可以创建一个承载不同超时时间消息的消息队列,但是这种方式有一个问题,如果消息队列中排在前面的消息没有到超时时间,即使后面的消息到了超时时间,先到超时时间的消息也不会进入死信队列,而是先检查排在最前面的消息队列是否到了超时时间,如果到了超时时间才会继续检查后面的消息。

第三种方式:使用rabbitmq的延时队列插件,实现同一个队列中有多个不同超时时间的消息,并按时间超时顺序出队
下载延迟插件

在 RabbitMQ 的 3.5.7 版本之后,提供了一个插件(rabbitmq-delayed-message-exchange)来实现延迟队列 ,同时需保证 Erlang/OPT 版本为 18.0 之后。

我这里 MQ 的版本是 3.10.0 现在去 GitHub 上根据版本号下载插件(其他版本也可以搜到)

安装插件并启用

我用的是 Docker 客户端,下载完成后直接把插件放在 /root 目录,然后拷贝到容器内plugins目录下(rabbitmq是容器的name,也可以使用容器id)

docker cp /home/208/rabbitmq_delayed_message_exchange-3.10.0.ez rabbitmq:/plugins

进入 Docker 容器

docker exec -it rabbitmq /bin/bash

在plugins内启用插件

#先执行,解除防火墙限制,增加文件权限
umask 0022rabbitmq-plugins enable rabbitmq_delayed_message_exchange

退出容器

exit

重启 RabbitMQ

docker restart rabbitmq

通过UI查看

如何使用?
消费者
java 复制代码
import cn.hutool.core.map.MapUtil;
import com.jyx.model.OrderingOk;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;

@Configuration
public class DelayConsumer {
    // 声明队列
    @Bean
    public Queue DelayQueue(){
        return QueueBuilder.durable("Delay_01").build();
    }
    // 声明交换机
    @Bean
    public CustomExchange DelayExchange(){
        HashMap<String, Object> map = MapUtil.of("x-delayed-type", "direct");
        return new CustomExchange("Delay_E01","x-delayed-message",  true, false,map);
    }
    // 绑定交换机和队列
    @Bean
    public Binding DelayBinding(Queue DelayQueue,CustomExchange DelayExchange){
        return  BindingBuilder.bind(DelayQueue).to(DelayExchange).with("RK01").noargs();
    }
    // 声明消费者
    @RabbitListener(queues = "Delay_01")
    public void receive(OrderingOk message)  {
        System.out.println("DelayConsumer接收到消息:" +message);
    }

}
生产者
java 复制代码
import com.jyx.model.OrderingOk;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class DelayProducer {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    // 生产者 发送消息
    public void send(OrderingOk message) {
        rabbitTemplate.convertAndSend("Delay_E01","RK01", message, message1 -> {
            int id = message.getId();
            int ttl= 0;
            if (id == 1) {
                ttl =id* 5*1000;
            } else if (id == 2) {
                ttl =id* 5*1000;
            } else if (id == 3) {
                ttl =id* 5*1000;
            } else if (id == 4) {
                ttl =id* 5*1000;
            }
            
            // 延迟交换机使用的delay参数,设置消息的延期时长,单位是微妙
            message1.getMessageProperties().setDelay(ttl);
            // 消息持久化默认是持久化
            message1.getMessageProperties().setDeliveryMode(MessageDeliveryMode.NON_PERSISTENT);
            return message1;
        });
        System.out.println("发送消息:" + message);
    }
}
相关推荐
Swift社区2 小时前
在 Swift 中实现字符串分割问题:以字典中的单词构造句子
开发语言·ios·swift
没头脑的ht2 小时前
Swift内存访问冲突
开发语言·ios·swift
没头脑的ht2 小时前
Swift闭包的本质
开发语言·ios·swift
wjs20242 小时前
Swift 数组
开发语言
吾日三省吾码3 小时前
JVM 性能调优
java
stm 学习ing3 小时前
FPGA 第十讲 避免latch的产生
c语言·开发语言·单片机·嵌入式硬件·fpga开发·fpga
湫ccc4 小时前
《Python基础》之字符串格式化输出
开发语言·python
弗拉唐4 小时前
springBoot,mp,ssm整合案例
java·spring boot·mybatis
oi775 小时前
使用itextpdf进行pdf模版填充中文文本时部分字不显示问题
java·服务器