RabbitMQ-死信队列常见用法

目录

一、什么是死信

二、什么是死信队列

[​编辑 三、第一种情景:消息被拒绝时](#编辑 三、第一种情景:消息被拒绝时)

[四、第二种场景:. 消费者发生异常,超过重试次数 。 其实spring框架调用的就是 basicNack](#四、第二种场景:. 消费者发生异常,超过重试次数 。 其实spring框架调用的就是 basicNack)

[五、第三种场景: 消息的Expiration 过期时长或队列TTL过期时间。](#五、第三种场景: 消息的Expiration 过期时长或队列TTL过期时间。)

[六、 第四种情景: 消息队列达到最大容量](#六、 第四种情景: 消息队列达到最大容量)


一、什么是死信

在RabbitMQ 中充当主角的就是消息,在不同场景下,消息会有不同地表现。

死信就是消息在特定场景下的一种表现形式,这些场景包括:

  1. 消息被拒绝访问,即 RabbitMQ返回 basicNack 的信号时 或者拒绝basicReject

2. 消费者发生异常,超过重试次数 。 其实spring框架调用的就是basicNack

  1. 消息的Expiration 过期时长或队列TTL过期时间。

  2. 消息队列达到最大容量

上述场景经常产生死信,即消息在这些场景中时,被称为死信。

二、什么是死信队列

死信队列就是用于储存死信的消息队列,在死信队列中,有且只有死信构成,不会存在其余类型的消息。

死信队列在 RabbitMQ 中并不会单独存在,往往死信队列都会绑定这一个普通的业务消息队列,当所绑定的消息队列中,有消息变成死信了,那么这个消息就会重新被交换机路由到指定的死信队列中去,我们可以通过对这个死信队列进行监听,从而手动的去对这一消息进行补偿。 人工干预

三、第一种情景:消息被拒绝时

#设置消费者手动应答模式

java 复制代码
spring.rabbitmq.listener.simple.acknowledge-mode = manual
java 复制代码
package com.by.consumer;


import com.by.model.OrderingOk;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
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.io.IOException;

@Configuration
@Slf4j
public class DeadConsumer {
    //死信交换机
    @Bean
    public DirectExchange deadExchange() {
        return ExchangeBuilder.directExchange("Dead_E01").build();
    }

    //死信队列
    @Bean
    public Queue deadQueue1() {
        return QueueBuilder.durable("Dead_Q01").build();
    }

    //死信交换机与死信队列的绑定
    @Bean
    public Binding deadBinding1(Queue deadQueue1, DirectExchange deadExchange) {
        return BindingBuilder.bind(deadQueue1).to(deadExchange).with("RK_DEAD");
    }

    //业务队列
    @Bean
    public Queue queue1() {
        return QueueBuilder
                .durable("Direct_Q01")
                .deadLetterExchange("Dead_E01")
                .deadLetterRoutingKey("RK_DEAD")
                //.ttl(10*1000) //该属性是队列的属性,设置消息的过期时间,消息在队列里面停留时间n毫秒后,就会把这个消息投递到死信交换机,针对的是所有的消息
                //.maxLength(20) //设置队列存放消息的最大个数,x-max-length属性值,当队列里面消息超过20,会把队列之前的消息依次放进死信队列
                .build();
    }

    //业务交换机
    @Bean
    public DirectExchange exchange() {
        return ExchangeBuilder.directExchange("Direct_E01").build();
    }

    //业务交换机与队列的绑定
    @Bean
    public Binding binding1(Queue queue1, DirectExchange exchange) {
        return BindingBuilder.bind(queue1).to(exchange).with("RK01");
    }

    //@RabbitListener(queues = "Direct_Q01")
//    public void receiveMessage(OrderingOk msg) {
//        log.info("消费者1 收到消息:"+ msg );
//        int  i= 5/0;
//    }

    @RabbitListener(queues = "Direct_Q01")
    public void receiveMessage(OrderingOk msg, Message message, Channel channel) throws IOException {

        long deliveryTag = message.getMessageProperties().getDeliveryTag();

        System.out.println("消费者1 收到消息:" + msg + " tag:" + deliveryTag);

        channel.basicReject(deliveryTag, false);
//        try {
//            // 处理消息...
//            int  i= 5/0;
//            // 如果处理成功,手动发送ack确认 ,Yes
//            channel.basicAck(deliveryTag, false);
//        } catch (Exception e) {
//            // 处理失败,可以选择重试或拒绝消息(basicNack或basicReject)  NO
//            channel.basicNack(deliveryTag, false, false); // 并重新入队
//
//        }
    }
}

四、第二种场景:. 消费者发生异常,超过重试次数 。 其实spring框架调用的就是basicNack

一般要和自动重启一起使用,否则死信队列收不到消息

java 复制代码
#设置消费者自动应答模式
spring.rabbitmq.listener.simple.acknowledge-mode = auto
#开启自动应答重试机制
spring.rabbitmq.listener.simple.retry.enabled=true
java 复制代码
package com.by.consumer;


import com.by.model.OrderingOk;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
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.io.IOException;

@Configuration
@Slf4j
public class DeadConsumer {
    //死信交换机
    @Bean
    public DirectExchange deadExchange() {
        return ExchangeBuilder.directExchange("Dead_E01").build();
    }

    //死信队列
    @Bean
    public Queue deadQueue1() {
        return QueueBuilder.durable("Dead_Q01").build();
    }

    //死信交换机与死信队列的绑定
    @Bean
    public Binding deadBinding1(Queue deadQueue1, DirectExchange deadExchange) {
        return BindingBuilder.bind(deadQueue1).to(deadExchange).with("RK_DEAD");
    }

    //业务队列
    @Bean
    public Queue queue1() {
        return QueueBuilder
                .durable("Direct_Q01")
                .deadLetterExchange("Dead_E01")
                .deadLetterRoutingKey("RK_DEAD")
                //.ttl(10*1000) //该属性是队列的属性,设置消息的过期时间,消息在队列里面停留时间n毫秒后,就会把这个消息投递到死信交换机,针对的是所有的消息
                //.maxLength(20) //设置队列存放消息的最大个数,x-max-length属性值,当队列里面消息超过20,会把队列之前的消息依次放进死信队列
                .build();
    }

    //业务交换机
    @Bean
    public DirectExchange exchange() {
        return ExchangeBuilder.directExchange("Direct_E01").build();
    }

    //业务交换机与队列的绑定
    @Bean
    public Binding binding1(Queue queue1, DirectExchange exchange) {
        return BindingBuilder.bind(queue1).to(exchange).with("RK01");
    }

    //@RabbitListener(queues = "Direct_Q01")
//    public void receiveMessage(OrderingOk msg) {
//        log.info("消费者1 收到消息:"+ msg );
//        int  i= 5/0;
//    }

    @RabbitListener(queues = "Direct_Q01")
    public void receiveMessage(OrderingOk msg, Message message, Channel channel) throws IOException {

        long deliveryTag = message.getMessageProperties().getDeliveryTag();

        System.out.println("消费者1 收到消息:" + msg + " tag:" + deliveryTag);
        int a=10/0;
//        channel.basicReject(deliveryTag, false);
//        try {
//            // 处理消息...
//            int  i= 5/0;
//            // 如果处理成功,手动发送ack确认 ,Yes
//            channel.basicAck(deliveryTag, false);
//        } catch (Exception e) {
//            // 处理失败,可以选择重试或拒绝消息(basicNack或basicReject)  NO
//            channel.basicNack(deliveryTag, false, false); // 并重新入队
//
//        }
    }
}

五、第三种场景: 消息的Expiration 过期时长或队列TTL过期时间。

java 复制代码
    //业务队列
    @Bean
    public Queue queue1() {
        return QueueBuilder
                .durable("Direct_Q01")
                .deadLetterExchange("Dead_E01")
                .deadLetterRoutingKey("RK_DEAD")
                .ttl(10*1000) //该属性是队列的属性,设置消息的过期时间,消息在队列里面停留时间n毫秒后,就会把这个消息投递到死信交换机,针对的是所有的消息
                //.maxLength(20) //设置队列存放消息的最大个数,x-max-length属性值,当队列里面消息超过20,会把队列之前的消息依次放进死信队列
                .build();
    }

六、 第四种情景: 消息队列达到最大容量

java 复制代码
    //业务队列
    @Bean
    public Queue queue1() {
        return QueueBuilder
                .durable("Direct_Q01")
                .deadLetterExchange("Dead_E01")
                .deadLetterRoutingKey("RK_DEAD")
//                .ttl(10*1000) //该属性是队列的属性,设置消息的过期时间,消息在队列里面停留时间n毫秒后,就会把这个消息投递到死信交换机,针对的是所有的消息
                .maxLength(5) //设置队列存放消息的最大个数,x-max-length属性值,当队列里面消息超过5,会把队列之前的消息依次放进死信队列
                .build();
    }
java 复制代码
    /**
     * 测试直联交换机
     *
     * @throws IOException
     * @throws InterruptedException
     */
    @Test
    void contextLoads() throws IOException, InterruptedException {
        for (int i = 0; i < 8; i++) {
            OrderingOk orderingOk = OrderingOk.builder().id(1).name("张三"+i).build();
            directProvide.send(orderingOk);
        }
       
        System.in.read();
    }

id为1,2,3的被装进了死信队列,因为数据太老,业务队列优先要新的数据

相关推荐
Java_2017_csdn4 小时前
OFC、ERP、OMS、WMS、TMS 对比-详解
java
励志不掉头发的内向程序员5 小时前
【从零写一个CAD 03】三个 double 值得单独一个类吗:把视图变换抽成 View
开发语言·c++·qt·学习·系统架构
PHP实战开发录5 小时前
PHP接口大整数为什么变了
开发语言·php
临床数据科学和人工智能兴趣组8 小时前
在R语言中, 使用 as.factor() 函数转换数值型变量
开发语言·r语言
andyweike12 小时前
php笔记
开发语言·笔记·php
EatFan12 小时前
Spring Boot 4 落地观察:从 yudao-cloud、matecloud、JPower 看国产脚手架的升级路线与迁移清单
java·spring boot·后端·spring cloud·微服务·后端开发·jdk 21
Maiko Star12 小时前
* LangChain 提示词模板详解:ChatPromptTemplate 的使用与高级特性
java·人工智能·langchain
Circ.13 小时前
Python 调试 Litellm 本地大模型接口:模型列表与对话接口实操踩坑记录
开发语言·python
现任明教教主~14 小时前
Thinkphp站群蜘蛛池SaaS系统YanyvSEO含多用户/积分/六大引擎计费/易支付对接
java·开发语言·spring
Zhou14113614 小时前
SpringSecurity_02_授权与高级功能
开发语言·python