Rabbitmq实现延时队列的方式一

本文介绍了如何在SpringAMQP环境下使用死信队列(DeadLetterExchanges)配合TTL特性处理定时发送的消息,但指出其可能存在的先进先出问题,并预告了使用延迟队列作为解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第一种方式:利用两个特性:Time to Live(TTL)、Dead Letter Exchanges(DLX) {A队列过期-   >    转发 给B队列}

也就是用的死信队列

我直接使用代码及输出结果来演示了

1.先把死信队列、死信交换机、 普通队列都定义出来,交换机与队列之间的关系绑定在代码中也是有注释说明

( ̄(工) ̄)代码如下:

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

@Configuration
public class QueueDLX {

    //死信队列
    public static final String QUEUEDLX_NAME = "queuedlx_name";
    //死信交换机
    public static final String EXCHANGEDLX_NAME = "exchangedlx_name";
    //普通队列
    public static final String QUEUE_NAME = "queue_name";


    //死信队列绑定死信交换机
    @Bean(QUEUEDLX_NAME)
    public Queue queueDLX() {
        return QueueBuilder.durable(QUEUEDLX_NAME)
                             //这里是死信队列的特有特性,
                            // 具有该特性才可以进行转发给交换机
                .withArgument("x-dead-letter-exchange", EXCHANGEDLX_NAME)
                .withArgument("x-dead-letter-routing-key", EXCHANGEDLX_NAME).build();
    }

    //死信交换机
    @Bean(EXCHANGEDLX_NAME)
    public DirectExchange EXCHANGEDLX_NAME(){
        return new DirectExchange(EXCHANGEDLX_NAME);
    }

    //普通队列
    @Bean(QUEUE_NAME)
    public Queue QUEUE_NAME(){
        return new Queue(QUEUE_NAME,true);
    }

    //死信交换机绑定普通队列
    @Bean
    public Binding bindingDLX(
            @Qualifier(EXCHANGEDLX_NAME) DirectExchange directExchange,
            @Qualifier(QUEUE_NAME)Queue queue){
        return BindingBuilder.bind(queue).to(directExchange).with(EXCHANGEDLX_NAME);
    }


}

2.服务启动后会去管理页面可以看到都成功注册好了

交换机

队列

3.发送者进行测试发送消息,并指定死亡时间

( ̄(工) ̄)代码如下:

     @Autowired
    private RabbitTemplate rabbitTemplate;



     /**
     * 测试死信消息
     */
    @Test
    public void sendTTLDLX(){
        System.out.println(new Date());

        String str = "{'id' :'2'}";

                                       //发送消息给死信队列
        rabbitTemplate.convertAndSend(QueueDLX.QUEUEDLX_NAME, str.getBytes(), new 
            MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                                                  //存活时间 毫秒  2分钟
                message.getMessageProperties().setExpiration("1000");
                return message;
            }
        });
    }

4.消费者监听消息队列

( ̄(工) ̄)代码如下:

/**
     * 监听消息(死信消息)
     * @param msg
     */
    @RabbitListener(queues = {QueueDLX.QUEUE_NAME})
    public void listener(@Payload Object msg) throws UnsupportedEncodingException {

        Message message = (Message) msg;
        String str = new String(message.getBody(),"utf-8");
        System.out.println("收到死信队列的消息:"+new Date());
        System.out.println(str);

    }

下面我们进行测试:

5.发送id为1的消息,死亡时间为2分钟

6.发送id为2的消息,死亡时间为1秒

7.打开管理页面可以看到,两条消息都在死信队列中

8.查看消费者监听到的消息顺序

总结:使用死信队列这种方式是可以实现延迟发送消息的,但是由于消息是发送给了死信队列,那么队列的特点是什么?   先进先出,现在问题来了,先发的消息死亡时间如果比较长, 而后发的消息死亡时间比较短,即便后发的消息已经到达了死亡时间,也还是需要等待先发的那条消息到达死亡时间出去后, 后发 的这条消息才能出去队列,这就存在问题了。 可以使用   延迟插件实现 - 延迟队列(Delay Queue)模式,详情看下一篇文章!!!

配合一张图理解总结的这段话:

### 如何使用 RabbitMQ 实现延迟队列 #### 使用 RabbitMQ 的死信机制实现延迟队列 RabbitMQ 提供了一种通过 **死信交换器 (Dead Letter Exchange, DLX)** 和普通队列相结合的方式来实现延迟队列的功能。这种方法的核心在于利用消息的 TTL(Time To Live)属性,当消息超过设定的时间后会被自动丢弃并进入死信队列。 以下是具体的实现方法: 1. 配置两个队列:一个是带有 TTL 属性的消息队列,另一个是用于接收过期消息的死信队列。 2. 将死信队列绑定到一个死信交换器上,并配置相应的路由键。 3. 发布一条具有 TTL 的消息至初始队列,在消息到期后会自动被转移到死信队列中。 此过程的具体操作步骤已在参考资料中有提及[^2]。 #### 示例代码展示 下面是一个基于 Python 的 Pika 库实现 RabbitMQ 延迟队列的例子: ```python import pika import json from datetime import timedelta def publish_delayed_message(channel, exchange_name, routing_key, message_body, delay_ms): """ Publish a delayed message to the RabbitMQ queue. :param channel: The RabbitMQ channel object :param exchange_name: Name of the dead-letter exchange :param routing_key: Routing key for the dead-letter queue :param message_body: Message content as dictionary :param delay_ms: Delay time in milliseconds """ # Convert message body to JSON string message_json = json.dumps(message_body) # Set up properties with expiration and delivery mode props = pika.BasicProperties( expiration=str(delay_ms), # Expiration is set in milliseconds delivery_mode=2 # Persistent messages ) # Publish the message to the initial queue channel.basic_publish(exchange='', routing_key='delay_queue', properties=props, body=message_json) # Establish connection to RabbitMQ server connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) channel = connection.channel() # Declare queues channel.queue_declare(queue='delay_queue', arguments={ 'x-dead-letter-exchange': 'dl_exchange', 'x-dead-letter-routing-key': 'dead_letter_routing' }) channel.exchange_declare(exchange='dl_exchange', exchange_type='direct') channel.queue_declare(queue='dead_letter_queue') # Bind dead letter queue to exchange channel.queue_bind(exchange='dl_exchange', queue='dead_letter_queue', routing_key='dead_letter_routing') # Example usage message_content = {"order_id": "1001", "status": "pending"} publish_delayed_message(channel, '', 'dead_letter_routing', message_content, 5000) # 5 seconds delay print("Message published successfully.") # Close connection connection.close() ``` 上述代码展示了如何创建带延迟特性的队列以及发送延迟消息的过程。其中 `expiration` 参数定义了消息存活时间,单位为毫秒;一旦该时间段结束,未消费的消息即转入指定的死信队列。 对于更高级别的需求,还可以考虑启用官方插件 rabbitmq_delayed_message_exchange 来进一步优化延迟队列的行为[^4]。 #### 设置消息优先级 如果希望在延迟队列的基础上增加对不同重要程度事件的支持,则可通过设置队列的最大优先级参数 (`x-max-priority`) 并结合每条消息单独赋予其优先权值的方式达成目标[^5]。 --- ### 性能与可靠性考量 采用 RabbitMQ 构建延迟队列能够显著提升业务场景下的灵活性和稳定性,特别是在电商领域常见的订单超时取消等功能模块里表现尤为突出[^1][^3]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乖乖宝贝&

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值