日常记录-SpringBoot整合RabbitMQ第五节(死信)

一、死信

1、什么是死信

当一个队列中的消息满足下列情况之一时,可以成为死信(dead letter):

  1. 消息 TTL 过期;
  2. 队列达到最大长度(队列满了,无法再添加数据到 RabbitMQ中);
  3. 消息被拒绝(basic.reject 或 basic.nack)并且消息设置 requeue=false(不再重新入队);

默认情况下,死信会直接丢弃
在这里插入图片描述

2、消费失败成为死信

重试策略:

  1. RejectAndDontRequeueRecoverer:重试耗尽后,直接reject,丢失消息。是默认的处理策略
  2. ImmediateRequeueMessageRecoverer:重试耗尽后,返回nack,消息重新入队
  3. RepublishMessageRecoverer:重试耗尽后,将失败消息投递到指定的交换机

在失败重试策略中,默认的RejectAndDontRequeueRecoverer会在本地重试次数耗尽后,发送reject给RabbitMQ,消息变成死信,被丢弃。(如果你用了RepublishMessageRecoverer策略,记得关了,不然消息有可能会丢到该策略绑定的队列中去)

我们可以给队列添加一个死信交换机,给死信交换机绑定一个死信队列。这样消息变成死信后也不会丢弃,而是最终投递到死信交换机,路由到与死信交换机绑定的死信队列。

3、定义死信交换机和死信队列

死信交换机和死信队列也是普通的交换机和队列,所以定义如下:

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


//死信交换机和死信队列也是普通的交换机和队列
@Configuration
public class DeadQueueConfig {
    
    

    //定义死信交换机
    @Bean
    public DirectExchange deadLetterExchange() {
    
    
        return ExchangeBuilder.directExchange("dead.letter.exchange").build();
    }


    //定义死信队列
    @Bean
    public Queue deadLetterQueue() {
    
    
        return new Queue("dead.letter.queue",true,false,false);
    }

    //交换机和队列绑定
    @Bean
    public Binding deadLetterQueueBinding(Queue deadLetterQueue, DirectExchange deadLetterExchange) {
    
    
        return BindingBuilder.bind(deadLetterQueue).to(deadLetterExchange).with("dl");
    }
}

4、如何绑定死信交换机、队列

绑定死信交换机和死信队列

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

import java.util.HashMap;
import java.util.Map;


@Configuration
public class TestDeadQueueConfig {
    
    

    @Bean
    public DirectExchange testDeadLetterExchangeExchange() {
    
    
        return ExchangeBuilder.directExchange("test.dead.letter.exchange").build();
    }



    @Bean
    public Queue testDeadLetterQueue() {
    
    


     return QueueBuilder.durable("test.dead.letter.queue")
             //test.dead.letter.queue队列绑定死信交换机
             .deadLetterExchange("dead.letter.exchange")
             //死信交换机和死信队列绑定 routingKey = dl
             .deadLetterRoutingKey("dl")
             .build();

        /*Map<String, Object> args = new HashMap();
        // DLX(死信交换机)
        args.put("x-dead-letter-exchange", "死信队列交换机的名称");
        // DLK(死信路由key)
        args.put("x-dead-letter-routing-key", "死信消息路由的routingKey");
        // TTL(time-to-live存活时间)
        args.put("x-message-ttl", 10000);
        return new Queue("test.dead.letter.queue",true,false,false,args);*/

    }

    //交换机和队列绑定
    @Bean
    public Binding testDeadLetterQueueBinding(Queue testDeadLetterQueue, DirectExchange testDeadLetterExchangeExchange) {
    
    
        return BindingBuilder.bind(testDeadLetterQueue).to(testDeadLetterExchangeExchange).with("test.dead.letter");
    }
}

在这里插入图片描述

5、消息失败后投递到死信

模拟生产者

import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class DeadQueueTest {
    
    

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Test
    void test(){
    
    
       //模拟生产者
       rabbitTemplate.convertAndSend("test.dead.letter.exchange","test.dead.letter","进行死信测试");


    }
}

模拟消费者


import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class DeadQueueListener {
    
    

    @RabbitListener(queues = "test.dead.letter.queue")
    public void testDeadLetterQueueMsg(String msg){
    
    

        System.out.println("test.dead.letter.queue收到消息:"+msg);

        //模拟:处理消息中出现了异常
        int i = 1/0;

        System.out.println("消息处理完毕!");
    }
}

在这里插入图片描述
在这里插入图片描述
消息成功投递到死信队列

6、消息超时投递到死信

默认情况下,消息是不会过期的,如果不设置任何消息过期的相关参数,那么消息是不会过期的,即使消息没被消费掉,也会一直存储在队列中。

如果设置了TTL,超过此时间后,消息被自动删除。

  1. 通过队列属性设置:队列中所有消息都有相同的过期时间
  2. 对消息进行单独设置:每条消息TTL可以不同
  3. 同时使用2种方式,过期时间以最小的数值为准。

1、演示队列超时TTL,投递到死信队列

定义队列,并且给他设置过期时间

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

@Configuration
public class TTLQueueConfig {
    
    


    @Bean
    public DirectExchange ttlExchange(){
    
    
        return ExchangeBuilder.directExchange("ttl.exchange").build();
    }

    //定时队列,设置过期时间,并且绑定死信交换机
    @Bean
    public Queue ttlQueue(){
    
    
        return QueueBuilder.durable("ttl.queue")
                //设置队列的超时时间为10s
                .ttl(10*1000)
                //给队列设置死信交换机,名称为dead.letter.exchange 设置投递死信时的RoutingKey为dl
                .deadLetterExchange("dead.letter.exchange")
                .deadLetterRoutingKey("dl")
                .build();
    }

    @Bean
    public Binding ttlBinding(Queue ttlQueue, DirectExchange ttlExchange){
    
    
        return BindingBuilder.bind(ttlQueue).to(ttlExchange).with("test.ttl.queue");
    }


}

模拟生产者

import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class TTLQueueTest {
    
    

    @Autowired
    private RabbitTemplate rabbitTemplate;

    //模拟生产者
    @Test
    public void test(){
    
    
        rabbitTemplate.convertAndSend("ttl.exchange","test.ttl.queue","这个队列10秒后过期,然后到死信队列");
    }


}

启动服务
在这里插入图片描述
调用生产者后
在这里插入图片描述
在这里插入图片描述

2、演示消息超时TTL,投递到死信队列

沿用测试队列超时的队列以及死信交换机

import org.junit.jupiter.api.Test;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.time.LocalTime;

@SpringBootTest
public class TTLQueueTest {
    
    

    @Autowired
    private RabbitTemplate rabbitTemplate;

    //模拟生产者
    @Test
    public void testTTLMessage() {
    
    
        String msgStr = "消息TTL demo,发送时间是:" + LocalTime.now();

        Message message = MessageBuilder
                .withBody(msgStr.getBytes())
                //设置消息TTL为5秒
                .setExpiration("5000")
                .build();

        //发送消息时:
        //  如果消息和队列都设置了TTL,则哪个TTL短,哪个生效
        //  如果消息和队列只设置了一个TTL,则直接以设置的为准
        rabbitTemplate.convertAndSend("ttl.exchange", "test.ttl.queue", message);
    }



}

使用场景:用户下单,如果用户在15 分钟内未支付,则自动取消订单等等。

猜你喜欢

转载自blog.csdn.net/qq407995680/article/details/132142406