RabbitMQ基础篇(九)-死信队列(DLX)

死信队列(DLX)

消费者在消费消息过程中出现意外导致消费失败即称为“死信”。而不希望这些执行失败的消息丢失,需要存储到另一个队列当中时,这种队列即为“死信队列”。
消息出现一下情况会导致 “死信”

  1. 消息被否定,消费者使用 channel.basicNack或channel.basicReject,并且requeue被设置为false时。

  2. 消息超过过期时间。消息在队列的存活时间超过了设置的生存时间(TTL)

  3. 消息数量超出队列长度(消息溢出)


以下将以“消息溢出”为案例

消费者

public class NormalConsumer {
    // 死信队列名
    private static final String DEAD_QUEUE_NAME = "dead-queue";
    // 死信交换机
    private static final String DEAD_EXCHANGE_NAME = "dead-exchange";
    // 普通队列名称
    private static final String NORMAL_QUEUE_NAME = "normal-queue";
    // 普通交换机名称
    private static final String NORMAL_EXCHANGE_NAME = "normal-exchange";
    public static final String NORMAL_ROUTING_KEY = "normal-demo";
    public static final String DEAD_ROUTING_KEY = "dead-demo";

    public static void main(String[] args) throws Exception, TimeoutException {
        Connection connection = RabbitConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        // 声明交换机
        channel.exchangeDeclare(DEAD_EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
        channel.exchangeDeclare(NORMAL_EXCHANGE_NAME, BuiltinExchangeType.DIRECT);

        // 声明队列
        Map<String, Object> normalArguments = new HashMap<>();
        // 死信队列绑定配置:死信交换机、死信routingKey、普通队列长度限制(超出长度变为死信)
        normalArguments.put("x-dead-letter-exchange", DEAD_EXCHANGE_NAME);
        normalArguments.put("x-dead-letter-routing-key", DEAD_ROUTING_KEY);
        normalArguments.put("x-max-length", 4);
        channel.queueDeclare(NORMAL_QUEUE_NAME, false, false, false, normalArguments);

        // 声明死信队列
        Map<String, Object> deadArguments = new HashMap<>();
        channel.queueDeclare(DEAD_QUEUE_NAME, false, false, false, deadArguments);

        // 绑定普通交换机和普通队列
        channel.queueBind(NORMAL_QUEUE_NAME, NORMAL_EXCHANGE_NAME, NORMAL_ROUTING_KEY);
        // 绑定死信交换机和死信队列
        channel.queueBind(DEAD_QUEUE_NAME, DEAD_EXCHANGE_NAME, DEAD_ROUTING_KEY);

        System.out.println("normal consumer:waiting message...");

        //消息消费成功之后的回调
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            String messageStr = new String(message.getBody(), StandardCharsets.UTF_8);
            if (messageStr.contains("5")) {
                System.out.println("mock ==> 请手动停止NomalConsumer程序,重启消费者,模拟普通队列的消息超出长度,导致死信");
                try {
                    Thread.sleep(100000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("normal consumer:" + messageStr);
        };
        channel.basicConsume(NORMAL_QUEUE_NAME, true, deliverCallback, consumer -> {
        });
    }
}

死信消费者

public class DeadConsumer {
    // 死信队列名
    private static final String DEAD_QUEUE_NAME = "dead-queue";

    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = RabbitConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        System.out.println("dead consumer: waiting message...");
        DeliverCallback deadCallback = (consumerTag, message) -> {
            System.out.println("dead consumer: " + new String(message.getBody()));
        };
        channel.basicConsume(DEAD_QUEUE_NAME, true, deadCallback, consumerTag -> {
        });
    }
}

消息提供者

public class NormalAndDeadProducer {
    // 普通交换机名称
    private static final String NORMAL_EXCHANGE_NAME = "normal-exchange";
    public static final String NORMAL_ROUTING_KEY = "normal-demo";

    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = RabbitConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        // 死信消息TTL时间
        AMQP.BasicProperties properties = new AMQP.BasicProperties()
                .builder()
                .expiration("10000")
                .build();

        for (int i = 0; i < 10; i++) {
            String message = "message info index is " + i;
            channel.basicPublish(NORMAL_EXCHANGE_NAME, NORMAL_ROUTING_KEY, properties, message.getBytes(StandardCharsets.UTF_8));
        }

    }
}

请按顺序执行以下步骤:

  1. 启动 消费者(NormalConsumer)
  2. 启动 死信消费者(DeadConsumer)
  3. 启动 消息提供者(NormalAndDeadProducer)
  4. 此刻可以看到消费者消费到了一半,这时立即关闭消费者程序的运行

  1. 重新启动一次 消息提供者,造成队列消息溢出
  2. 查看 死信消费者 控制台,可以看到,有一部分消息进入了死信队列并被 死信消费者 消费了

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值