【RabbitMQ教程】第五章 —— RabbitMQ - 死信队列

news2024/11/25 19:51:35

在这里插入图片描述

                                                                  💧 【 R a b b i t M Q 教程】第五章—— R a b b i t M Q − 死信队列 \color{#FF1493}{【RabbitMQ教程】第五章 —— RabbitMQ - 死信队列} RabbitMQ教程】第五章——RabbitMQ死信队列💧          


🌷 仰望天空,妳我亦是行人.✨
🦄 个人主页——微风撞见云的博客🎐
🐳 《数据结构与算法》专栏的文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺
💧 《Java学习笔记》专栏的文章是本人在Java学习中总结的一些知识点~ 💐
🥣 《每天一点小知识》专栏的文章可以丰富你的知识库,滴水成河~ 🌊
🥕 《RabbitMQ》专栏的文章是在学习尚硅谷课程时整理的笔记,方便复习巩固~ 🍑
🪁 希望本文能够给读者带来一定的帮助~🌸文章粗浅,敬请批评指正!🐥


文章目录

  • 🌊RabbitMQ - 死信队列
    • 死信的概念
    • 死信的来源
    • 死信实战
      • 死信之 T T l
      • 死信之最大长度
      • 死信之消息被拒
  • 🐳结语


🌊RabbitMQ - 死信队列

死信的概念

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

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

#死信的来源

死信的来源

  • 消息 TTL 过期

    TTL是Time To Live的缩写, 也就是生存时间

  • 队列达到最大长度

    队列满了,无法再添加数据到 mq 中

  • 消息被拒绝

    (basic.reject 或 basic.nack) 并且 requeue=false.

死信实战

在这里插入图片描述

死信之 T T l

消费者 C1 代码:

/**
 * 死信队列 - 消费者01
 */
public class Consumer01 {

    //普通交换机名称
    private static final String NORMAL_EXCHANGE = "normal_exchange";
    //死信交换机名称
    private static final String DEAD_EXCHANGE = "dead_exchange";

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

        //声明死信和普通交换机 类型为 direct
        channel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT);
        channel.exchangeDeclare(DEAD_EXCHANGE, BuiltinExchangeType.DIRECT);

        //声明死信队列
        String deadQueue = "dead-queue";
        channel.queueDeclare(deadQueue, false, false, false, null);
        //死信队列绑定:队列、交换机、路由键(routingKey)
        channel.queueBind(deadQueue, DEAD_EXCHANGE, "lisi");

        //正常队列绑定死信队列信息
        Map<String, Object> params = new HashMap<>();
        //正常队列设置死信交换机 参数 key 是固定值
        params.put("x-dead-letter-exchange", DEAD_EXCHANGE);
        //正常队列设置死信 routing-key 参数 key 是固定值
        params.put("x-dead-letter-routing-key", "lisi");

        //正常队列
        String normalQueue = "normal-queue";
        channel.queueDeclare(normalQueue, false, false, false, params);
        channel.queueBind(normalQueue, NORMAL_EXCHANGE, "zhangsan");

        System.out.println("等待接收消息........... ");
        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody(), "UTF-8");
            System.out.println("Consumer01 接收到消息" + message);
        };
        channel.basicConsume(normalQueue, true, deliverCallback, consumerTag -> {
        });
    }

}

生产者代码

public class Producer {
    private static final String NORMAL_EXCHANGE = "normal_exchange";

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

        channel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT);
        //设置消息的 TTL 时间 10s
        AMQP.BasicProperties properties = new AMQP.BasicProperties().builder().expiration("10000").build();
        //该信息是用作演示队列个数限制
        for (int i = 1; i < 11; i++) {
            String message = "info" + i;
            channel.basicPublish(NORMAL_EXCHANGE, "zhangsan", properties, message.getBytes());
            System.out.println("生产者发送消息:" + message);
        }

    }
}

启动 C1 ,之后关闭消费者,模拟其接收不到消息。再启动 Producer
在这里插入图片描述
消费者 C2 代码:

以上步骤完成后,启动 C2 消费者,它消费死信队列里面的消息

public class Consumer02 {
    //死信交换机名称
    private static final String DEAD_EXCHANGE = "dead_exchange";

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

        //声明交换机
        channel.exchangeDeclare(DEAD_EXCHANGE, BuiltinExchangeType.DIRECT);
        //声明队列
        String deadQueue = "dead-queue";
        channel.queueDeclare(deadQueue, false, false, false, null);
        channel.queueBind(deadQueue, DEAD_EXCHANGE, "lisi");

        System.out.println("等待接收死信消息........... ");
        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody(), "UTF-8");
            System.out.println("Consumer02 接收到消息" + message);
        };
        channel.basicConsume(deadQueue, true, deliverCallback, consumerTag -> {
        });
    }
}

在这里插入图片描述

死信之最大长度

1、消息生产者代码去掉 TTL 属性
在这里插入图片描述
2、C1 消费者修改以下代码**(启动之后关闭该消费者 模拟其接收不到消息)**
在这里插入图片描述

//设置正常队列的长度限制,例如发10个,4个则为死信
params.put("x-max-length",6);

注意此时需要把原先队列删除 因为参数改变了

3、C2 消费者代码不变(启动 C2 消费者)
在这里插入图片描述

死信之消息被拒

1、消息生产者代码同上生产者一致

2、C1 消费者代码(启动之后关闭该消费者 模拟其接收不到消息)

拒收消息 “info5”

public class Consumer01 {

    //普通交换机名称
    private static final String NORMAL_EXCHANGE = "normal_exchange";
    //死信交换机名称
    private static final String DEAD_EXCHANGE = "dead_exchange";

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

        //声明死信和普通交换机 类型为 direct
        channel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT);
        channel.exchangeDeclare(DEAD_EXCHANGE, BuiltinExchangeType.DIRECT);

        //声明死信队列
        String deadQueue = "dead-queue";
        channel.queueDeclare(deadQueue, false, false, false, null);
        //死信队列绑定:队列、交换机、路由键(routingKey)
        channel.queueBind(deadQueue, DEAD_EXCHANGE, "lisi");
        
        //正常队列绑定死信队列信息
        Map<String, Object> params = new HashMap<>();
        //正常队列设置死信交换机 参数 key 是固定值
        params.put("x-dead-letter-exchange", DEAD_EXCHANGE);
        //正常队列设置死信 routing-key 参数 key 是固定值
        params.put("x-dead-letter-routing-key", "lisi");
//        //设置正常队列的长度限制,例如发10个,4个则为死信
//        params.put("x-max-length",6);
        
        //正常队列
        String normalQueue = "normal-queue";
        channel.queueDeclare(normalQueue, false, false, false, params);
        channel.queueBind(normalQueue, NORMAL_EXCHANGE, "zhangsan");

        System.out.println("等待接收消息........... ");
        
        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody(), "UTF-8");
            if (message.equals("info5")) {
                System.out.println("Consumer01 接收到消息" + message + "并拒绝签收该消息");
                //requeue 设置为 false 代表拒绝重新入队 该队列如果配置了死信交换机将发送到死信队列中
                channel.basicReject(delivery.getEnvelope().getDeliveryTag(), false);
            } else {
                System.out.println("Consumer01 接收到消息" + message);
                channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
            }

        };
        //开启手动应答
        channel.basicConsume(normalQueue, false, deliverCallback, consumerTag -> {
        });
    }

}

在这里插入图片描述
3、C2 消费者代码不变

启动消费者 1 然后再启动消费者 2

在这里插入图片描述


在这里插入图片描述


🐳结语

🐬初学一门技术时,总有些许的疑惑,别怕,它们是我们学习路上的点点繁星,帮助我们不断成长。

🐟文章粗浅,希望对大家有帮助!

💧下一篇 -->【RabbitMQ教程】第四章 —— RabbitMQ - 延迟队列

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/647443.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringCloud:分布式事务Seata

1.什么是分布式事务 分布式事务就是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上&#xff0c;简单的说&#xff0c;就是一次大的操作由不同的小操作组成&#xff0c;这些小的操作分布在不同的服务器上&#xff0c;且属…

【Flutter】Flutter 创建每个页面公用的底部框

文章目录 一、 前言二、 创建公用底部框的步骤1. 创建一个公用的底部框 Widget2. 在页面中使用公用的底部框 Widget 三、 示例&#xff1a;电商应用中的公用底部框1. 创建电商应用的底部框 Widget2. 在电商应用的各个页面中使用底部框 Widget 四、 完整代码示例五、 一些注意事…

第一次ubuntu wsl ssh远程登录各种报错+解决

第一次ubuntu wsl ssh远程登录各种报错+解决 最新推荐文章于 2023-04-13 20:23:43 发布 kh3064 于 2020-11-03 15:12:16 发布 1869 收藏 5 文章标签: ubuntu

计算理论导引实验三:构造图灵机

计算理论导引实验三&#xff1a;构造图灵机 实验描述形式化定义图灵机M的状态图 算法设计与描述状态转移关系类键盘输入及逻辑处理类 编码实现测试运行 实验描述 要求构造一个能够识别语言L的图灵机。语言L的描述和实验内容如下图所示 形式化定义 根据实验描述&#xff0c;可…

【批量修改后缀名】如何批量去修改文件后缀名(亲测图文结合)

【写在前面】前段时间&#xff0c;因为素材需要&#xff0c;就去之前我制作相册的一个网站上下载了一批照片&#xff0c;但是照片下载下来的格式居然是.png!600*0&#xff0c;这种格式的也打不开&#xff0c;于是乎我自己就吭哧吭哧的去一个个的修改&#xff0c;然后我一想他娘…

EBU5476 Microprocessor System Design 知识点总结_5 GPIO

GPIO General Purpose Input Output, Memory-Mapped IO 把设备&#xff0c;控制等寄存器映射到内存里。好处就是访问设备方式和内存一样&#xff0c;也不用设计复杂的IO电路&#xff0c;便捷&#xff1b;缺点在于占用了内存空间。 Peripheral-Mapped IO IO有一块专门的存储…

Vue|单文件组件与脚手架安装

一、单文件组件1.1 介绍1.2 文件组成1.3 加深认知 二、脚手架安装2.1 什么是脚手架?2.2 使用镜像2.3 全局安装vue/cli2.4 创建并启动项目 一、单文件组件 1.1 介绍 [.vue]文件&#xff0c;称为单文件组件&#xff0c;是Vue.js自定义的一种文件格式&#xff0c;一个.vue文件就…

AST使用(二)

//在此之前&#xff0c;先了解下path和node/*path指的是路径 其常用的方法当前路径所对应的源代码 : path.toString判断path是什么type&#xff0c;使用path.isXXX 这个方法 : if(path.isStringLiteral()){}获取path的上一级路径 : let parent path.parentPath;获取path的子…

nginx的安装及代理和负载均衡设置

一、通过yum方式进行安装 官网参考地址&#xff1a;https://nginx.org/en/linux_packages.html#RHEL 1.1 安装好依赖 执行下面的命令安装 sudo yum install yum-utils1.2、 先配置好yum源 新建文件/etc/yum.repos.d/nginx.repo&#xff0c;文件内容&#xff1a; [nginx-s…

一个成熟的软件测试工程师应该具备那些“技能”

1、良好的沟通 相信大家都在网上看到过各种吐槽程序员不解风情的段子&#xff0c;开怀大笑之余深思&#xff0c;作为一个测试工程师又何尝不是如此&#xff1f;通常沟通技能成为横亘在测试工程师与其他合作部门之间的万丈鸿沟&#xff0c;也成为测试工程师成长的最大瓶颈。下面…

Vector-常用CAN工具 - 以太网报文收发方向

目录 Rx 和 Tx 标记 Example&#xff1a;从 CANoe 向 ECU 发送以太网数据包 用例 2&#xff1a;从 ECU 接收以太网数据包 如何仅显示物理或虚拟通信 如何仅显示 Rx 或 Tx 以太网数据包 VN5000以太网包过滤 1、什么是硬件过滤&#xff1f; 2、什么时候使用硬件过滤&…

useEffect,useLayoutEffect的基础知识和底层机制

useEffect 是 React 中一个重要的 Hook&#xff0c;用来处理组件的副作用操作。它的基础知识包括两个方面&#xff1a;执行时机和参数。 执行时机&#xff1a; useEff ect 的执行时机包括两种情况&#xff1a; 组件挂载时&#xff0c;即第一次渲染之后。组件更新时&#xff…

智能垃圾分类小程序,流量主变现,外卖cps权益变现,uniCloud云开发无需购买服务器和域名,助力每一位创业者。

技术优势 基于 uniapp uniCloud 研发&#xff0c;无需购买服务器和域名&#xff0c;uniCloud 是 DCloud 联合阿里云、腾讯云 serverless 构建。从此不用关心服务器运维、弹性扩容、大并发承载、防DDoS攻击等&#xff0c;轻松应对高并发应用&#xff0c; 传统小程序开通流量主…

Qt 多语言实现

简介 Qt Linguist 提供了一套加速应用程序翻译和国际化的工具。Qt 使用单一的源码树和单一的应用程序二进制包就可同时支持多个语言和书写系统。 使用 QTranslator 来加载生成的 qm 文件&#xff0c;就可以让程序显示指定的语言。 // 国际化翻译 QString language "CH…

项目Es、kafka、mysql容量评估方案和服务器资源预估方案

目录 1、Es 评估计划 一个接口jmeter压测qps 1万, logstash 读取日志文件写入es Logstash配置 Es容量变化前后差值/1万 * 1.67 * &#xff08;1副本数&#xff09; ~ 次接口es 容量 &#xff08;日志数据30kb&#xff09; 影响es存储的主要原因 通过 kibana 查看 堆栈》索…

管理类联考——英语——技巧篇——阅读理解

一、阅读理解A节选项的点 1.正确答案的五大特征 (1)“主题为王”原则&#xff1a;即正确答案通常与文章的中心思想、主旨大意有关。 (2)正确答案的特点&#xff1a;语言简化、反话正说、正话反说、关键词替换。 (3)正确答案要选相对的&#xff0c;不选绝对的。正确答案通常含有…

编译原理期末速成-LL(1)文法、FIRST集、FOLLOW集

文章目录 LL(1)文法的条件LL(1)分析法构造FIRST(α)构造FOLLOW(A)习题强化 LL(1)文法的条件 文法不含左递归 对于文法中每一个非终结符A的各个产生式的候选首符集两两不相交。即若 对于文法中的每个非终结符A&#xff0c;若它存在某个候选首符集包含ε&#xff0c;则 这里&am…

面试被问到:测试计划和测试方案有什么区别?

面试的时候&#xff0c;很多小伙伴都被面试官问过这个问题 “测试计划和测试方案有什么区别”&#xff1f; 到底有什么区别呢&#xff1f;我们先好好了解下这两个文档。 一、测试计划 1、测试计划是什么&#xff1f; 测试计划是组织管理层面的文件&#xff0c;从组织管理的…

Jetpack Compose 中使用 CameraX 拍照和录制视频

在 Android 开发的历史中&#xff0c;Camera 的 API 是一直受人诟病的&#xff0c;使用过的人都知道&#xff0c;直观的感觉就是配置复杂、臃肿、难用、不易理解&#xff0c;从官方关于 Camera 的 API 迭代路线可以看出官方也在尝试着不断改进开发者关于Camera的使用体验&#…

ChatGPT编程

ChatGPT问答 问题一&#xff1a;如何合理分配时间问题二&#xff1a;以下是提高工作效率的建议&#xff1a;问题三&#xff1a;如何培养兴趣问题四&#xff1a;软件和硬件谁重要问题五: 设计模式如何熟练运用问题六:C语言编程冒泡排序 问题一&#xff1a;如何合理分配时间 这里…