使用RabbitMQ 插件实现延迟队列

接着上一篇。
SpringBoot整合RabbitMQ实现延迟队列
了解到在消息属性上设置 TTL 的方式,消息可能并不会按时“死亡“,因为 RabbitMQ 只会检查第一个消息是否过期,如果过期则丢到死信队列,如果第一个消息的延时时长很长,而第二个消息的延时时长很短,第二个消息并不会优先得到执行,这就是用死信做延迟队列的一个缺陷。

如果不能实现在消息粒度上的 TTL,并使其在设置的 TTL 时间及时死亡,就无法设计成一个通用的延时队列。那如何解决呢,接下来我们就去解决该问题。

安装延时队列插件

在官网上下载 https://www.rabbitmq.com/community-plugins.html
在这里插入图片描述
版本不能乱下载。
在这里插入图片描述

下载rabbitmq_delayed_message_exchange 插件,然后解压放置到 RabbitMQ 的插件目录。
/usr/lib/rabbitmq/lib/rabbitmq_server-3.8.8/plugins
在这里插入图片描述

 cp rabbitmq_delayed_message_exchange-3.8.0.ez /usr/lib/rabbitmq/lib/rabbitmq_server-3.8.8/plugins


在这里插入图片描述
在这里插入图片描述

进入 RabbitMQ 的安装目录下的 plgins 目录,执行下面命令让该插件生效,然后重启 RabbitMQ

rabbitmq-plugins enable rabbitmq_delayed_message_exchange

在这里插入图片描述
插件安装成功,重启MQ

systemctl restart rabbitmq-server

现在去MQ可视化后台管理添加交换机,发现多了一个选项
在这里插入图片描述

代码架构图

在这里新增了一个队列 delayed.queue,一个自定义延迟交换机 delayed.exchange,绑定关系如下:
在这里插入图片描述

配置文件类代码

在我们自定义的交换机中,这是一种新的交换类型,该类型消息支持延迟投递机制 消息传递后并
不会立即投递到目标队列中,而是存储在 mnesia(一个分布式数据系统)表中,当达到投递时间时,才
投递到目标队列中。

package com.xiang.springboot_rabbitmq.config;

import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;

/**
 * 延迟队列配置
 *
 */

@Configuration
public class DelayedQueueConfig {

    //交换机
    public static final String DELAYED_EXCHANGE ="delayed_exchange";
    //队列
    public static final String DELAYED_QUEUE ="delayed_queue";
    //routeingKey
    public static final String DELAYED_ROUTINGKEY ="delayed_routingKey";

    //声明延迟交换机
    @Bean
    public CustomExchange delayedExchange(){
        HashMap<String, Object> arguments = new HashMap<>();
        //自定义交换机的类型
        arguments.put("x-delayed-type", "direct");
        /**
         * 交换机名
         * 交换机类型
         * 持久化
         * 自动删除
         */
        return new CustomExchange(DELAYED_EXCHANGE,"x-delayed-message",true,false,arguments);
    }

    /**
     * 声明队列
     * @return
     */
    @Bean
    public Queue delayedQueue(){
        return new Queue(DELAYED_QUEUE);
    }

    //延迟交换机和队列绑定
    @Bean
    public Binding delayedQueueBindingDelayedExchange(Queue delayedQueue,CustomExchange delayedExchange){
        return BindingBuilder.bind(delayedQueue).to(delayedExchange).with(DELAYED_ROUTINGKEY).noargs();
    }
}

消息生产者代码

    @GetMapping("/delay/{message}/{delayedTime}")
    public void delayedTimeMessage(@PathVariable String message,@PathVariable Integer delayedTime){
        log.info("当前时间:{} 发送一条信息给delayed交换机{},delayedTime:{}",new Date().toString(),message,delayedTime);
        rabbitTemplate.convertAndSend(DelayedQueueConfig.DELAYED_EXCHANGE,DelayedQueueConfig.DELAYED_ROUTINGKEY,message,(msg -> {
            //发送消息 并设置delayedTime
            msg.getMessageProperties().setDelay(delayedTime);
            return msg;
        }));

    }

消息消费者代码

import com.rabbitmq.client.Channel;
import com.xiang.springboot_rabbitmq.config.DelayedQueueConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * 基于查询的监听延迟队列的消息
 */

@Component
@Slf4j
public class delayedConsumer {


    @RabbitListener(queues = DelayedQueueConfig.DELAYED_QUEUE)
    public void receiveMessage(Message message, Channel channel){
        String msg = new String(message.getBody());
        log.info("当前时间{},收到延迟队列的消息:{}",new Date().toString(),msg);
    }

}

启动进行测试
127.0.0.1:8080/ttl/delay/张三/20000
127.0.0.1:8080/ttl/delay/李四/2000

输出结果
在这里插入图片描述

结论

延时队列在需要延时处理的场景下非常有用,使用 RabbitMQ 来实现延时队列可以很好的利用RabbitMQ 的特性,如:消息可靠发送、消息可靠投递、死信队列来保障消息至少被消费一次以及未被正确处理的消息不会被丢弃。另外,通过 RabbitMQ 集群的特性,可以很好的解决单点故障问题,不会因为单个节点挂掉导致延时队列不可用或者消息丢失。

当然,延时队列还有很多其它选择,比如利用 Java 的 DelayQueue,利用 Redis 的 zset,利用 Quartz
或者利用 kafka 的时间轮,这些方式各有特点,看需要适用的场景

  • 7
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
RabbitMQ可以通过插件的方式实现延迟队列。以下是一种常用的方法: 1. 首先,确保你的RabbitMQ服务器已经安装了rabbitmq_delayed_message_exchange插件。如果没有安装,你需要先安装该插件。 2. 创建一个延迟队列,你可以使用如下代码声明一个延迟队列: ```python import pika connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) channel = connection.channel() args = { 'x-delayed-type': 'direct', } channel.exchange_declare(exchange='delayed_exchange', exchange_type='x-delayed-message', arguments=args) channel.queue_declare(queue='delayed_queue') channel.queue_bind(queue='delayed_queue', exchange='delayed_exchange', routing_key='routing_key') ``` 3. 发送延迟消息到延迟队列,你可以使用如下代码发送延迟消息: ```python import pika connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) channel = connection.channel() properties = pika.BasicProperties(headers={'x-delay': 5000}) # 设置延迟时间,单位为毫秒 channel.basic_publish( exchange='delayed_exchange', routing_key='routing_key', body='Hello, delayed message!', properties=properties ) ``` 4. 消费延迟队列中的消息,你可以使用如下代码消费延迟消息: ```python import pika connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) channel = connection.channel() def callback(ch, method, properties, body): print("Received delayed message:", body) channel.basic_consume(queue='delayed_queue', on_message_callback=callback, auto_ack=True) channel.start_consuming() ``` 以上是通过插件实现延迟队列的方法,你可以根据自己的需求进行调整和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值