RabbitMQ--死信队列

目录

一、死信队列介绍

1.死信

2.死信的来源

2.1 TTL

2.2 死信的来源

3.死信队列 

4.死信队列的用途

二、死信队列的实现

1.导入依赖 pom.xml

2.application.properties

3.配置类

4.生产者

5.业务消费者(正常消费者)

6.死信队列消费者


一、死信队列介绍

1.死信

        死信顾名思义就是没办法被消费的消息;

2.死信的来源

2.1 TTL

        什么是TTL?

        TTL(Time To Live)翻译为生存时间,是指消息在队列中可以存活的时间,如果消息在队列中存活的时间超过了TTL,那么消息就会被标记为死信,然后进入死信队列;

2.2 死信的来源

  • 消息TTL过期;
  •  队列达到最大长度: 队列满了无法再添加消息,就会成为死信,然后进入死信队列;
  • 消息被拒绝,比如我们设置了消息的应答模式为手动应但是没有调用ack方法,那么消息就会被标记为死信,然后进入死信队列;

3.死信队列 

        我们能了解到,消息生产者生产消息,消费者消费(处理消息),消息生产者发送消息到队列,消费者从队列中获取消息,某些消息会无法被消费就会成为死信,自然而然的,我们需要一个队列来存储死信,而这个队列就被成为死信队列;

4.死信队列的用途

首先呢一个事物能够存在就说明他有存在的理由,死信队列其实一般来做一个定时的作用 例如:

  • 在保证订单业务中的消息数据不丢失,当消息没有被处理或者是超出了TTL时间,那么我们就可以将他放在死信队列中,然后定时去消费死信队列中的消息,然后进行相应的处理;
  • 如果这个消息是被动的,就是说我们想让他被消费但是没有被消费那么其实就是保证了消息的不丢失;
  • 如果是一个主动的,我们设置了我们需要的TTL,那么就可以成为一个定时功能。比如取消支付功能;

1.2.1 延迟队列:

如果是这个消息使我们故意的想让发到死信队列中,其实我们可以将他叫做为延时队列,我们可以设置一个时间,比如我们想让这个消息延迟10分钟再发送到死信队列中,那么我们就可以将这个消息发送到延迟队列中,然后定时去消费延迟队列中的消息,然后进行相应的处理;

二、死信队列的实现

1.导入依赖 pom.xml

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.amqp</groupId><artifactId>spring-rabbit-test</artifactId><scope>test</scope></dependency>
</dependencies>

2.application.properties

spring.application.name=springboot-rabbitmq
server.port=8080
#默认地址就是127.0.0.1:5672,如果是服务器的rabbitmq就改下
spring.rabbitmq.host=192.168.174.130
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=admin
spring.rabbitmq.listener.type=simple
#设置为false,会丢弃消息或者重新发步到死信队列
spring.rabbitmq.listener.simple.default-requeue-rejected=false
#手动签收
spring.rabbitmq.listener.simple.acknowledge-mode=manual
#虚拟主机目录
spring.rabbitmq.virtual-host=/

3.配置类

@Configuration
public class rabbitMQConf {//普通交换机的名字public static final String NORMAL_EXCHANGE = "normalExchange";//普通队列的名字public static final String NORMAL_QUEUE = "normalQueue";//死信交换机的名字public static final String DEAD_EXCHANGE = "deadExchange";//死信队列的名字public static final String DEAD_QUEUE = "deadQueue";/*** 普通交换机*/@Beanpublic DirectExchange normalExchange() {return new DirectExchange(NORMAL_EXCHANGE);}/*普通队列*/@Beanpublic Queue normalQueue() {return new Queue(NORMAL_QUEUE);}/*** 死信交换机 死信队列*/@Beanpublic DirectExchange deadExchange() {return new DirectExchange(DEAD_EXCHANGE);}/*** 死信队列*/@Beanpublic Queue deadQueue() {return new Queue(DEAD_QUEUE);}/*** 绑定正常队列*/@Beanpublic Binding normalBinding() {return BindingBuilder.bind(normalQueue()).to(normalExchange()).with("normal");}/*** 死信队列绑定* @return*/@Beanpublic Binding deadBinding() {return BindingBuilder.bind(deadQueue()).to(deadExchange()).with("dead");}
}

4.生产者

@Slf4j
@RestController
@RequestMapping("/test")
public class SendMessageController {@Autowiredprivate RabbitTemplate rabbitTemplate;@GetMapping("/sendMsg/{msg}")public String sendMsg(@PathVariable(value = "msg") String msg) {log.info("send msg:" + msg);rabbitTemplate.convertAndSend(NORMAL_EXCHANGE, "normal", msg);return "success";}
}

5.业务消费者(正常消费者)

@Service
@Slf4j
public class NormalMessageReceiver {/*** 消费消息*/@RabbitListener(queues = NORMAL_QUEUE)@SneakyThrowspublic void receive(Message msg, Channel channel) {String s = msg.getBody().toString();String s1 = new String(msg.getBody());log.info("这个是toString方式得出来的s:{}", s);log.info("这个是new String方式得出来的s:{}", s1);boolean ack=true;Exception exception=null;try {if (s1.contains("dead")){throw new RuntimeException("dead letter exception");}} catch (RuntimeException e) {ack=false;exception=e;}if (!ack){System.out.println("error msg{ }"+exception.getMessage());//设置死信消息channel.basicNack(msg.getMessageProperties().getDeliveryTag(),false,false);}else {channel.basicAck(msg.getMessageProperties().getDeliveryTag(),false);}System.out.println("正常消息消费者收到消息:" + msg);}
}

6.死信队列消费者

@Component
public class DeadMessageReceiver {/*** 死信队列*/@RabbitListener(queues = rabbitMQConf.DEAD_QUEUE)public void receiveA(Message message, Channel channel) throws IOException {System.out.println("DeadMessageA{}" + new String(message.getBody()));channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);}
}

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

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

相关文章

Linux系统安全整改实践指南

在当前信息化高速发展的时代&#xff0c;Linux操作系统凭借其开源、稳定和高效的特点&#xff0c;在服务器市场占据着举足轻重的地位。然而&#xff0c;随着网络威胁的日益复杂化&#xff0c;确保Linux系统的安全性成为了一项至关重要的任务。本文旨在提供一套全面的Linux系统安…

leetcode 1319.连通网络的操作次数

思路&#xff1a;DFS&#xff08;连通块&#xff09; 其实一开始的时候&#xff0c;并不知道这道题的精髓在哪&#xff0c;总想着&#xff0c;啊&#xff1f;这怎么用图论的思想做啊&#xff1f; 细细思考之后&#xff0c;这道题还是比较有意思的&#xff0c;需要有一定的数据…

# Mysql 数据库区分大小写吗?

Mysql 数据库区分大小写吗&#xff1f; 1、MySQL 数据库在区分大小写方面有特定的行为&#xff0c;这取决于多个因素&#xff0c;包括操作系统、配置参数以及使用的字符集。 2、数据库名和表名&#xff1a; 在 Linux 系统中&#xff0c;数据库和表名是严格区分大小写的。 而…

【前端性能优化】深入解析重绘和回流,构建高性能Web界面

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 &#x1f3af; 引言&#xff1a;探索Web性能的基石&#x1f3d7;️ 基础概念&#xff1a;什么是重绘和回流&#xff1f;&#x1f4cc; 回流&#xff08;Reflow&#xff09;&#x1f4cc; 重绘&#xff08;Repaint&#xff0…

蓝桥杯国赛每日一题:交换瓶子(图论,环,贪心)

题目描述&#xff1a; 有 N 个瓶子&#xff0c;编号 1∼N&#xff0c;放在架子上。 比如有 5 个瓶子&#xff1a; 2 1 3 5 4要求每次拿起 2 个瓶子&#xff0c;交换它们的位置。 经过若干次后&#xff0c;使得瓶子的序号为&#xff1a; 1 2 3 4 5对于这么简单的情况&#…

使用Flask部署Web应用:从入门到精通

文章目录 第一部分&#xff1a;准备工作第二部分&#xff1a;部署Flask应用到AWS部署到AWS Lambda 第三部分&#xff1a;部署Flask应用到腾讯云服务器部署到腾讯云服务器 第四部分&#xff1a;优化和扩展结论 在现代软件开发中&#xff0c;Web应用的部署是一个至关重要的环节。…

使用Flask-SocketIO构建实时Web应用

文章目录 准备工作编写代码编写HTML模板运行应用 随着互联网的发展&#xff0c;实时性成为了许多Web应用的重要需求之一。传统的HTTP协议虽然可以实现实时通信&#xff0c;但是其长轮询等机制效率低下&#xff0c;无法满足高并发、低延迟的需求。为了解决这一问题&#xff0c;诞…

python常见数据的存取

python数据的存取 python数据的存取数据的保存3.1.1 保存list3.1.2 保存Dict3.1.3 保存Set3.1.4 保存Dataframe3.1.5 保存Matrix 3.2 数据的读取3.2.1 读取txt文件中的数据3.2.2 读取excel文件中的数据3.2.3 读取csv文件中的数据3.2.4 读取stata文件中的数据3.2.5 读取R文件中的…

计算机发展史故事【14】

大象踢踏舞 如果要把电脑50 年的历史划分为两个不同的阶段&#xff0c;那么&#xff0c;1981 年无疑是个分界线。就在那一年&#xff0c;IBM 公司推出个人电脑PC 机&#xff0c;使人类社会大步跨进个人电脑新时代。今天&#xff0c;全世界正在使用的PC 机已达到2 亿台&#xf…

视频拼接融合产品的产品与架构设计(三)内存和显存单元数据迁移

上一篇文章 视频拼接融合产品的产品与架构设计(二) 这一篇沉下先来&#xff0c;彻底放弃了界面&#xff0c;界面最终的体现是最后要做的&#xff0c;现在要做的是产品的架构&#xff0c;使用链式架构方式迁移数据。同时增加插件口&#xff0c;方便编程序。 插件架构 为了视频…

Android 开机过程画面

Android 开机画面流程 Android 开机动画加载流程涉及bootloader、内核、Android 核心进程、Android文件系统 Bootloader(引导加载程序):当设备启动时,首先由 Bootloader 加载。Bootloader 位于设备的固化存储器中,其主要功能是初始化硬件并启动操作系统。 内核加载:Boo…

Kivy 项目51斩百词 3 屏幕页面转换

MRWord/pages/indexpage/index.py class IndexPage(GridLayout):# 初始化def __init__(self, **kwargs):super().__init__(**kwargs)staticmethoddef index_to_upload():App.get_running_app().screen_manager.current "Upload"定义了一个名为 IndexPage 的类&…

短剧奔向小程序,流量生意如何开启?

随着移动互联网的飞速发展&#xff0c;小程序作为一种轻量级、易传播的应用形态&#xff0c;逐渐在各个领域展现出其独特的商业价值。而最近爆火的短剧小视频作为一种受众广泛的娱乐形式&#xff0c;与小程序结合后&#xff0c;不仅为观众提供了更为便捷的观看体验&#xff0c;…

代码随想录算法训练营第五十三天|LeetCode1143.最长公共子序列、LeetCode1035.不相交的线、LeetCode53.最大子序和

LeetCode 1143 最长公共子序列 题目链接&#xff1a;1143. 最长公共子序列 - 力扣&#xff08;LeetCode&#xff09; 【解题思路】 1.确定dp数组含义 dp[i][j] &#xff1a;长度为[0,i-1]的字符串和长度为[0,j-1]的字符串的最长公共子序列为dp[i][j] 2.确定递推公式 text1[i…

Linux线程(三)死锁与线程同步

目录 一、什么是死锁 死锁的四个必要条件 如何避免死锁 避免死锁算法 二、Linux线程同步 三 、条件变量 1、条件变量基本原理 2、条件变量的使用 3、条件变量使用示例 为什么 pthread_cond_wait 需要互斥量? 一、什么是死锁 死锁是计算机科学中的一个概念&#xff0c;…

Python-VBA函数之旅-type函数

目录 一、type函数的常见应用场景 二、type函数使用注意事项 三、如何用好type函数&#xff1f; 1、type函数&#xff1a; 1-1、Python&#xff1a; 1-2、VBA&#xff1a; 2、推荐阅读&#xff1a; 个人主页&#xff1a; https://myelsa1024.blog.csdn.net/ 一、type函…

设计一个游戏的基本博弈框架

设计一个游戏的基本博弈框架&#xff0c;玩家通过操作改变某个数值&#xff0c;这个数值的变动会引发一系列实时变化&#xff0c;并且当这些数值累计到特定阈值时&#xff0c;会导致游戏中出现其他变化&#xff0c;可以分为以下几个步骤&#xff1a; 1. 确定游戏类型和主题 首…

【rk3568】linux与amp内存分配

关于AMP问题&#xff1a; 1、内存分配&#xff1a;linux端与rtos端内存要分割开。 2、在device/rockchip/rk3568/BoardConfig-rk3568-evb1-ddr4-v10.mk中会定义内存地址需要注意在linux端也需要保留rtos使用的的内存地方&#xff0c;否则可能rtos用的的内存会被linux端使用到…

UE4_照亮环境_不同雾效的动态切换

一、问题及思路&#xff1a; 我们在一个地图上&#xff0c;经常切换不同的区域&#xff0c;不同的区域可能需要不同的色调&#xff0c;例如暖色调的野外或者幽暗的山洞&#xff0c;这两种环境上&#xff0c;雾效的选用肯定不一样&#xff0c;夕阳西下的户外用的就是偏暖的色调&…