rabbitmq死信队列

死信队列

先从概念解释上搞清楚这个定义,死信,顾名思义就是无法被消费的消息,字面意思可以这样理解,一般来说,producer 将消息投递到 broker 或者直接到queue 里了,consumer 从 queue 取出消息进行消费,但某些时候由于特定的原因导致 queue 中的某些消息无法被消费,这样的消息如果没有后续的处理,就变成了死信,有死信自然就有了死信队列。

应用场景:为了保证订单业务的消息数据不丢失,需要使用到 RabbitMQ 的死信队列机制,当消息消费发生异常时,将消息投入死信队列中.还有比如说: 用户在商城下单成功并点击去支付后在指定时间未支付时自动失效

1、死信来源

消息 TTL 过期

队列达到最大长度(队列满了,无法再添加数据到 mq 中)

消息被拒绝(basic.reject 或 basic.nack)并且 requeue=false.

2、消息TTL过期

创建普通队列 和 交换机,还有死信队列,交换机

public static final String NORMAL_EXCHANGE = "normal_exchange";
    public static final String NORMAL_QUEUE = "normal_queue";
    public static final String DEAD_EXCHANGE = "dead_exchange";
    public static final String DEAD_QUEUE = "dead_queue";

    public static void main(String[] args) throws Exception {
        Channel channel = RabbitMQUtils.getChannel();

        //声明并创建 死信交换机和队列 建立交换机与队列的映射关系
        channel.queueDeclare(DEAD_QUEUE,false,false,false,null);
        channel.exchangeDeclare(DEAD_EXCHANGE,BuiltinExchangeType.DIRECT);
        channel.queueBind(DEAD_QUEUE,DEAD_EXCHANGE,"dead");


        //如果普通队列中出现死信消息,应该将此消息,交由死信交换机,放到对应的死信队列
        HashMap<String, Object> arguments = new HashMap<>();
        // 给普通队列设置死信交换机  注意:key是固定值
        arguments.put("x-dead-letter-exchange",DEAD_EXCHANGE);
        // 指定routerKey,死信交换机将数据发给哪个dead_queue
        arguments.put("x-dead-letter-routing-key","dead");
        channel.queueDeclare(NORMAL_QUEUE,false,false,false,arguments);

        //声明并创建 普通交换机和队列 建立交换机与队列的映射关系
        channel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT);
        channel.queueBind(NORMAL_QUEUE,NORMAL_EXCHANGE,"normal");


        DeliverCallback ackCallback = (consumerTag,delivery)->{
            System.out.println(consumerTag+ " 正在消费正常消息:"+ new String(delivery.getBody()));
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);
        };

        channel.basicConsume(NORMAL_QUEUE,false,ackCallback,(consumerTag)->{});
    }

开启当前的消费者,发现创建了两个交换机和队列,停止当前消费者,模拟消息不处理
在这里插入图片描述

创建生产者,设置消息的过期时间(10s),并启动

public static final String EXCHANGE_NAME = "normal_exchange";
    public static final String QUEUE_NAME = "normal_queue";

    public static void main(String[] args) throws Exception{
        Channel channel = RabbitMQUtils.getChannel();

        // 配置消息的TTL 过期时间
        AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder().expiration(String.valueOf(10 * 1000)).build();
        
        for (int i = 0; i < 10; i++) {
            String message = "你好啊"+i;
            channel.basicPublish(EXCHANGE_NAME,"normal",properties,message.getBytes("UTF-8"));
            System.out.println("发送消息成功");
        }
    }

发现10s后,normal_queue中的消息,全部到了dead_queue

在这里插入图片描述

在上述过程中,其实在消费者创建队列的时候,也可以设置消息的TTL,但是其实生产者设置消息的TTL是最灵活的。

启动死信队列的消费者

public static final String DEAD_QUEUE = "dead_queue";

    public static void main(String[] args) throws Exception {
        Channel channel = RabbitMQUtils.getChannel();

        DeliverCallback ackCallback = (consumerTag, delivery)->{
            System.out.println(consumerTag+ " 正在消费异常消息:"+ new String(delivery.getBody()));
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);
        };

        channel.basicConsume(DEAD_QUEUE,false,ackCallback,(consumerTag)->{});
    }

在这里插入图片描述

当前消费者,成功处理死信消息,死信队列消息为0
在这里插入图片描述

3、队列达到最大长度

上述代码一致,需要删除原先的队列,因为参数变了,在正常队列的消费者中添加一行配置,设置当前队列,可接收的最大消息数量

// 指定正常队列的最大接收的消息数量
 arguments.put("x-max-length",5);

在这里插入图片描述

1、启动生产者,关闭消费者,因为消费者,处理速度很快,可能发一条处理一条,那么队列长度永远也达不到5,永远满不了

在这里插入图片描述

可以看到,两个消费者各消费五条消息

在这里插入图片描述

在这里插入图片描述

4、消息被拒

修改普通消费者代码

DeliverCallback ackCallback = (consumerTag,delivery)->{
    String message = new String(delivery.getBody());
    // 模拟消息拒收, 拒收消息, 拒绝将该消息重新入队,消息发给死信交换机
    if(message.contains("7")){
        System.out.println("出于某种原因,拒收该消息:"+message );
        channel.basicReject(delivery.getEnvelope().getDeliveryTag(),false);
    }else{
     	System.out.println(consumerTag+ " 正在消费正常消息:"+ message);
    	channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);   
    }
};

在这里插入图片描述

在这里插入图片描述

个人博客:https://www.xiaoxuya.top/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

白鸽呀

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

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

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

打赏作者

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

抵扣说明:

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

余额充值