RabbitMQ死信队列基础代码实现

在这里插入图片描述

RabbitMQ死信队列官网:https://www.rabbitmq.com/dlx.html

1.死信队列

1.1.死信队列介绍

死信,死掉的信息,就是消费者未处理就已经丢失,例如消费者未启动,生产者发出消息至交换机,交换机没有找到相应的队列,此消息就会丢失。如果这些消息很重要,而我们又需要,现在就有一种方法可将这些死信消息存下来,那就是死信交换机DLX(Dead Letter Exchanges),DLX也没那么复杂,它就是一个普通的交换机,它可以是Topic也可以是Fanout、Direct等类型

实现步骤:

  1. 业务队列里配置好死信交换机routing key
  2. 消息发送到业务交换机
  3. 业务交换机转发到业务队列
  4. 业务队列将死信发送到死信交换机
  5. 再由死信交换机转发到死信队列

1.2.死信队列产生原因

在这里插入图片描述
由官网描述可知,死信队列产生原因有3条:

  • 拒绝:消息被队列拒绝接收
  • 超时:消息存活时间TTL(time to live)超时
  • 长度:队列中的消息长度达到最大值

1.3.死信队列作用

延迟队列的定义与实现

  • 定义:

    延迟队列存储的对象肯定是对应的延时消息,所谓"延时消息"是指当消息被发送以后,并不想让消费者立即拿到消息,而是等待指定时间后,消费者才拿到这个消息进行消费。

  • 实现:

    rabbitmq可以通过设置队列的 TTL死信路由 实现延迟队列

    • TTL:

    RabbitMQ可以针对Queue设置x-expires 或者 针对Message设置 x-message-ttl,来控制消息的生存时间,如果超时(两者同时设置以最先到期的时间为准),则消息变为dead letter(死信)

    • 死信路由DLX

    RabbitMQ的Queue可以配置x-dead-letter-exchangex-dead-letter-routing-key(可选)两个参数,如果队列内出现了dead letter,则按照这两个参数重新路由转发到指定的队列。

    • x-dead-letter-exchange:出现dead letter之后将dead letter重新发送到指定exchange
    • x-dead-letter-routing-key:出现dead letter之后将dead letter重新按照指定的routing-key发送

x-dead-letter-exchangex-dead-letter-routing-keyk-v 键值对中的固定key,写法固定

延迟队列使用场景
在这里插入图片描述
为什么不能用定时任务完成?

如果恰好在一次扫描后完成业务逻辑,那么就会等待两个扫描周期才能扫到过期的订单,不能保证时效性
在这里插入图片描述

2.代码实现

大致流程:
在这里插入图片描述

2.1.消费者代码实现

/**
 * Direct-消费者
 *
 * @Author: Ron
 * @Create: 2021 11:12
 */
public class Recv {

    // 死信队列
    private final static String DEAD_QUEUE_NAME = "dead_queue";

    // 业务队列
    private final static String QUEUE_NAME = "msg_queue";

    // 业务交换机
    private final static String EXCHANGE_NAME = "msg_exchange";

    // 死信交换机
    private final static String DEAD_EXCHANGE_NAME = "dead_exchange";

    public static void main(String[] argv) throws Exception {
        // 获取到连接
        Connection connection = ConnectionUtil.getConnection();
        // 获取通道
        Channel channel = connection.createChannel();

        // 交业务换机声明
        channel.exchangeDeclare(EXCHANGE_NAME, "direct");
        // 指定死信发送的死信交换机DLX
        Map<String, Object> agruments = new HashMap<String, Object>();
        agruments.put("x-dead-letter-exchange", DEAD_EXCHANGE_NAME);
        agruments.put("x-dead-letter-routing-key", "dead");

        //声明一个业务队列,为业务队列配置死信交换机和路由key
        channel.queueDeclare(QUEUE_NAME, true, false, false, agruments);

        // 绑定队列到交换机,同时指定需要订阅的routing key。订阅
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "msg");

        // 声明死信交换机
        channel.exchangeDeclare(DEAD_EXCHANGE_NAME, "direct");
        // 声明死信队列,存放死信消息
        channel.queueDeclare(DEAD_QUEUE_NAME, true, false, false, null);
        //将DLX和死信存放队列绑定,并产生一个路由key
        channel.queueBind(DEAD_QUEUE_NAME, DEAD_EXCHANGE_NAME, "dead");

        // 定义队列的消费者
        DefaultConsumer consumer = new DefaultConsumer(channel) {
            // 获取消息,并且处理,这个方法类似事件监听,如果有消息的时候,会被自动调用
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
                                       byte[] body) throws IOException {
                // body 即消息体
                String msg = new String(body);
                System.out.println(" [消费者2] received : " + msg + "!");
            }
        };
        // 监听队列,自动ACK
        channel.basicConsume(QUEUE_NAME, true, consumer);
    }
}

启动消费者
生成的交换机:
在这里插入图片描述

生成的队列:
在这里插入图片描述

2.2.生产者代码实现

/**
 * Direct-生产者
 * @Author: Ron
 * @Create: 2021 11:12
 */
public class Send {
    // 业务交换机
    private final static String EXCHANGE_NAME = "msg_exchange";

    public static void main(String[] argv) throws Exception {
        // 获取到连接
        Connection connection = ConnectionUtil.getConnection();
        // 获取通道
        Channel channel = connection.createChannel();
        // 声明exchange,指定类型为direct
        // 消息内容
        String message = "死信队列消息发送测试。。。";

        // 设置消息存活时间ttl为10秒
        AMQP.BasicProperties properties = new AMQP.BasicProperties
                .Builder()
                .deliveryMode(2)
                .contentEncoding("UTF-8")
                .expiration("10000")
                .build();
        
        // 消息发送至业务交换机
        channel.basicPublish(EXCHANGE_NAME, "msg",true, properties, message.getBytes());

        System.out.println(" [商品服务:] Sent '" + message + "'");

        channel.close();
        connection.close();
    }
}

关闭消费者代码,运行生产者代码,模拟消息未被消费者处理,超时
在这里插入图片描述
如果队列内出现了dead letter,则按照 x-dead-letter-exchangex-dead-letter-routing-key 这两个参数重新路由转发到指定的队列
在这里插入图片描述
最后,再通过监听该死信队列的消息来实现对消息的处理

查看死信队列中的具体信息:
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值