浅析RabbitMQ死信队列
原文首发于公众号【CSJerry】

在现代分布式系统中,消息队列扮演着至关重要的角色。它们可以实现应用程序之间的异步通信,并确保数据的可靠传输和处理。而在这个领域中,RabbitMQ作为一种强大而受欢迎的消息队列解决方案,具备了高效、可靠和灵活的特性。
然而,即使使用了RabbitMQ,我们仍然会遇到一些不可预料的情况,例如消费者无法处理某些消息、消息过期或者队列溢出等。为了解决这些问题,RabbitMQ引入了死信队列(Dead Letter Queue)的概念,为开发人员提供了一种有效的错误处理机制。
那么,究竟什么是死信队列呢?
本文结合Spring Boot使用RabbitMQ的死信队列,着重从是什么、为什么、怎么用几个方面对死信队列进行简单介绍。
1. 是什么:
- 死信队列(
Dead Letter Queue)是一种特殊的消息队列,用于存储无法被消费的消息。 - 当消息满足某些条件无法被正常消费时,将被发送到死信队列中进行处理。
- 死信队列提供了一种延迟处理、异常消息处理等场景的解决方案。
2. 为什么
- 用来处理消费者无法正确处理的消息,避免消息丢失或积压。
- 实现延迟消息处理,例如订单超时未支付,可以将该消息发送到死信队列,然后再进行后续处理。
- 用于实现消息重试机制,当消费者处理失败时,将消息重新发送到死信队列进行重试。
- 提高了系统的可伸缩性和容错性,能够应对高并发和异常情况。
3. 怎么用
- 在Spring Boot中配置和使用死信队列:
- 首先,在
pom.xml文件中添加RabbitMQ的依赖项。 - 然后,在
application.properties文件中配置RabbitMQ连接信息。 - 接下来,创建生产者和消费者代码,并通过注解将队列和交换机进行绑定。
- 在队列的声明中添加死信队列的相关参数,如
x-dead-letter-exchange和x-dead-letter-routing-key等。 - 最后,在消费者中编写处理消息的逻辑,包括对异常消息进行处理,并设置是否重新发送到死信队列。
- 首先,在
简而言之,死信队列可以认为是一个正常队列的备用队列(或者说是兜底队列),当正常队列的消息无法消费的时候mq会重新把该消息发送到死信交换机,由死信交换机根据路由键将消息投递到备用队列,启动服务备用方案。
消息从正常队列到死信队列的三种情况:
1、消息被否定确认使用
channel.basicNack或channel.basicReject,并且此时requeue属性被设置为false。2、消息在队列中的时间超过了设置的TTL())时间。
3、消息数量超过了队列的容量限制()。
当一个队列中的消息满足上述三种情况任一个时,改消息就会从原队列移至死信队列,若改队列没有绑定死信队列则消息被丢弃。
4. 实战
以下是一个简单的Spring Boot集成RabbitMQ的死信队列示例代码:
- 配置
spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5672
spring.rabbitmq.username=rabbit
spring.rabbitmq.password=123456
# 开启消费者手动确认
spring.rabbitmq.listener.type=direct# 发送到队列失败时的手动处理
spring.rabbitmq.listener.direct.acknowledge-mode=manual
spring.rabbitmq.publisher-returns=true# 发送到交换机手动确认
spring.rabbitmq.publisher-confirm-type=simple
- 配置类
@Configuration
@Slf4j
public class RabbitCof {@Resourceprivate MqKeys mqKeys;@Bean("normalQueue")public Queue normalQueue() {/*** 为普通队列绑定交换机*/Map<String, Object> args = new HashMap<>();args.put("x-dead-letter-exchange", mqKeys.DIE_EXCHANGE);args.put("x-dead-letter-routing-key", mqKeys.DIE_ROUTING_KEY);args.put("x-message-ttl", 1000); // 队列中的消息未被消费则1秒后过期return new Queue(mqKeys.NORMAL_QUEUE, true, false, false, args);}@Bean("normalExchange")public Exchange normalExchange() {return new DirectExchange(mqKeys.NORMAL_EXCHANGE);}@Bean("normalBind")public Binding normalBinding(@Qualifier("normalQueue") Queue normalQueue, @Qualifier("normalExchange") Exchange normalExchange) {return BindingBuilder.bind(normalQueue).to(normalExchange).with(mqKeys.ROUTING_KEY).noargs();}/*** 死信队列* @return*/@Bean("dieQueue")public Queue dlQueue() {return new Queue(mqKeys.DIE_QUEUE, true, false, false);}/*** 死信交换机* @return*/@Bean("dieExchange")public Exchange dlExchange() {return new DirectExchange(mqKeys.DIE_EXCHANGE);}@Bean("dieBind")public Binding dlBinding(@Qualifier("dieQueue") Queue dlQueue, @Qualifier("dieExchange") Exchange dlExchange) {return BindingBuilder.bind(dlQueue).to(dlExchange).with(mqKeys.DIE_ROUTING_KEY).noargs();}@Resourceprivate ConnectionFactory connectionFactory;@Beanpublic RabbitTemplate rabbitTemplate() {RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);/*** 消费者确认收到消息后,手动ack回调处理* spring.rabbitmq.publisher-confirm-type=simple*/rabbitTemplate.setConfirmCallback((CorrelationData correlationData, boolean ack, String cause)->{if(!ack) {log.info("消息投递到交换机失败,correlationData={} ,ack={}, cause={}", correlationData == null ? "null" : correlationData.getId(), ack, cause);} else {log.info("消息成功投递到交换机,correlationData={} ,ack={}, cause={}", correlationData == null ? "null" : correlationData.getId(), ack, cause);}});/*** 消息投递到队列失败回调处理* spring.rabbitmq.listener.direct.acknowledge-mode=manual* spring.rabbitmq.publisher-returns=true*/rabbitTemplate.setReturnsCallback((returnedMessage)->{Message message = returnedMessage.getMessage();log.error("分发到到队列失败, body->{}", message.getBody());});return rabbitTemplate;}
}
- 生产者类
@Component
public class Producer {@Resourceprivate MqKeys mqKeys;@Resourceprivate RabbitTemplate rabbitTemplate;public void sendMessage(String message) {rabbitTemplate.convertAndSend(mqKeys.NORMAL_EXCHANGE, mqKeys.ROUTING_KEY, message);}
}
- 消费者类
@Component
@RabbitListener(queues = "normal.queue")
@Slf4j
public class Consumer {@RabbitHandlerpublic void handleMessage(String data, Message message, Channel channel) {boolean success = false;int retryCount = 3;System.out.println(message.toString());long deliveryTag = message.getMessageProperties().getDeliveryTag();while (!success && retryCount-- > 0){try {// 处理消息log.info("收到消息: {}, deliveryTag = {}", data, deliveryTag);// 正常处理完毕,手动确认,此处不确认让他进入死信队列
// success = true;
// channel.basicAck(deliveryTag, false);Thread.sleep(3 * 1000L);}catch (Exception e){log.error("程序异常:{}", e.getMessage());}}// 达到最大重试次数后仍然消费失败if(!success){try {log.info("move to die queue");// 手动拒绝,移至死信队列/***deliveryTag – the tag from the received AMQP.Basic.GetOk or AMQP.Basic.Delivermultiple – true to reject all messages up to and including the supplied delivery tag; false to reject just the supplied delivery tag.requeue – true if the rejected message(s) should be requeued rather than discarded/dead-lettered*/channel.basicNack(deliveryTag, false, false);} catch (IOException e) {e.printStackTrace();}}}
}
以上代码演示了如何在Spring Boot中配置一个普通队列和一个死信队列,然后通过生产者发送消息到普通队列,在消费者中处理消息,并模拟了当发生异常时将消息重新发送到死信队列。
参考连接
-
[rabbit 官网]Dead Letter Exchanges — RabbitMQ
-
具体代码仓库
相关文章:
浅析RabbitMQ死信队列
原文首发于公众号【CSJerry】 在现代分布式系统中,消息队列扮演着至关重要的角色。它们可以实现应用程序之间的异步通信,并确保数据的可靠传输和处理。而在这个领域中,RabbitMQ作为一种强大而受欢迎的消息队列解决方案,具备了高…...
ELK 企业级日志分析系统(ElasticSearch、Logstash 和 Kiabana 详解)
目录 一.ELK简介 1.1ELK的概述 1.2ELK的组成 1.2.1 ElasticSearch 1.2.2 Logstash 1.2.3 Kibana 1.2.4 小总结 1.3可以添加其他组件 1.4filebeat 结合 logstash 带来好处 1.5日志处理的步骤 二.Elasticsearch 2.1Elasticsearch概述 2.2Elasticsearch核心概念 2.2.1接近…...
数学建模—多元线性回归分析
第一部分:回归分析的介绍 定义:回归分析是数据分析中最基础也是最重要的分析工具,绝大多数的数据分析问题,都可以使用回归的思想来解决。回归分析的人数就是,通过研究自变量X和因变量Y的相关关系,尝试去解释…...
win10 64位 vs2017 qt5.12.6 pcl1.9.1 vtk8.1.1配置安装步骤
由于我电脑中有 QT5.12.6 VS2017,就不介绍怎么安装了,只介绍cmake,pcl及vtk的配置步骤 为了便于后续QT的调用,以下所有安装路径中均不能出现中文及空格等 PCL自带VTK是不完整的,所以需要下载VTK源码进行重新编译使其…...
【项目 计网1】4.1 网络结构模式 4.2MAC地址、IP地址、端口
文章目录 第四章 Linux网络编程4.1 网络结构模式C/S结构(client-server)B/S结构(Browser/Server,浏览器/服务器模式) 4.2 4.3MAC地址、IP地址、端口(1)(2)MAC地址IP地址(…...
uni-app:分页实现多选功能
效果 代码解析 一、标签-列表 <view class"item_all" v-for"(item, index) in info" :key"index"><view class"position parameter-info text-over" :class"{checked_parameter: item.checked}" :data-id"i…...
问道管理:沪指窄幅震荡跌0.18%,有色、汽车等板块走低
3日早盘,沪指盘中窄幅震动下探,创业板逆市上扬;两市半日成交不足5000亿元,北向资金净卖出超15亿元。 到午间收盘,沪指跌0.18%报3255.88点,深成指跌0.23%,创业板指涨0.2%;两市算计成交…...
Kotlin 协程与 Flow
简介 Kotlin的Flow 是 Kotlin 在异步编程方面的一个重要组件,它提供了一种声明式的、可组合的、基于协程的异步编程模型。Flow 的设计灵感来自于 Reactive Streams、RxJava、Flux 和其他异步编程库,但它与 Kotlin 协程无缝集成,并提供了一种更…...
设备管理系统与物联网的融合:实现智能化设备监控和维护
在数字化时代,设备管理系统和物联网技术的融合为工业企业带来了巨大的变革和创新。本文将探讨设备管理系统与物联网的融合,重点介绍设备健康管理平台在实现智能化设备监控和维护方面的关键作用和优势。 一、设备管理系统与物联网的融合 随着物联网技术的…...
三、从官方源码精简出第1个FreeRTOS
1、官方源码下载 (1)进入FreeRTOS官网:FreeRTOS官网 (2)点击下载FreeRTOS。 (3)选择待示例的项目进行下载。 2、删减目录 (1)下载后解压的FreeRTOS文件如下图所示。 (2)删除下图中红框勾选的文件。 (3)删除"FreeRTOSv202212.01\FreeRTOS\Demo"目录下用…...
__call__函数的用法
__call__的用法 在 Python 中,类可以通过定义特殊方法 call 来使其实例对象可调用,就像调用普通的函数一样。当你在实例对象后面加上括号并传递参数时,Python 会自动调用这个对象的 call 方法。这使得你可以将类的实例对象当作函数来使用。 下…...
golang定时任务库cron实践
简介 cron一个用于管理定时任务的库,用 Go 实现 Linux 中crontab这个命令的效果。之前我们也介绍过一个类似的 Go 库——gron。gron代码小巧,用于学习是比较好的。但是它功能相对简单些,并且已经不维护了。如果有定时任务需求,还…...
Julia 流程控制
流程控制语句通过程序设定一个或多个条件语句来实现。在条件为 true 时执行指定程序代码,在条件为 false 时执行其他指定代码。 Julia 提供了大量的流程控制语句: 复合表达式:begin 和 ;。 条件表达式:if-elseif-else 和 ?: (三…...
问题解决方案
前端开发 1、npm安装的时候老是卡住 reify:rxjs: timing reifyNode:node_modules/vue/cli/node_modules 查看当前使用的那个镜像 nrm lsnpm ---------- https://registry.npmjs.org/yarn --------- https://registry.yarnpkg.com/cnpm --------- https://r.cnpmjs.org/taobao …...
kubernetes基于helm部署gitlab-operator
kubernetes基于helm部署gitlab-operator 这篇博文介绍如何在 Kubernetes 中使用helm部署 GitLab-operator。 先决条件 已运行的 Kubernetes 集群负载均衡器,为ingress-nginx控制器提供EXTERNAL-IP,本示例使用metallb默认存储类,为gitlab p…...
ChatGPT在在线客服和呼叫中心中的应用如何?
ChatGPT在在线客服和呼叫中心领域中有广泛的应用潜力,可以帮助企业提供更高效、个性化和满意度更高的客户服务体验。以下是详细的讨论: **1. 自动化客服:** ChatGPT可以用于自动化客服流程,通过自动回复用户的常见问题和查询&…...
C++多线程环境下的单例类对象创建
使用C无锁编程实现多线程下的单例模式 贺志国 2023.8.1 在多线程环境下创建一个类的单例对象,要比单线程环境下要复杂很多。下面介绍在多线程环境下实现单例模式的几种方法。 一、尺寸较小的类单例对象创建 如果待创建的单例类SingletonForMultithread内包含的成…...
“深入解析JVM内部机制:从字节码到垃圾回收“
标题:深入解析JVM内部机制:从字节码到垃圾回收 摘要:本文将从字节码生成、类加载、运行时数据区域和垃圾回收等方面深入解析JVM的内部机制,并通过示例代码展示其工作原理和实践应用。 正文: 一、字节码生成 JVM是基…...
音频系统项目与音频算法研究方向分类
+我V hezkz17进数字音频系统研究开发交流答疑群(课题组) 音频系统项目与音频算法研究方向分类 一 音频系统项目产品分类 1 收音机,数字收音机,复读机 2 耳机,蓝牙耳机,TWS蓝牙耳机, 3 立体声音箱,AI智能音箱, 4 音频功放,车载功放, 5 音响,普通音响,Soundbar音响…...
单例模式和工厂模式
目录 今日良言:关关难过关关过,步步难行步步行 一、单例模式 1.饿汉模式 2.懒汉模式 二、工厂模式 今日良言:关关难过关关过,步步难行步步行 一、单例模式 首先来解释一下,什么是单例模式。 单例模式也就是单个…...
serverless-http 与主流框架兼容性测试:Express、Koa、Hapi、Fastify 全面对比
serverless-http 与主流框架兼容性测试:Express、Koa、Hapi、Fastify 全面对比 【免费下载链接】serverless-http Use your existing middleware framework (e.g. Express, Koa) in AWS Lambda 🎉 项目地址: https://gitcode.com/gh_mirrors/se/server…...
2026年支持人民币计价的金价追踪APP有哪些
家人们谁懂啊!上周我发小蹲了3个月的50克古法金镯子终于下手,结账的时候才傻了眼:她之前用来盯金价的APP默认是美元离岸价,自己换算的时候忘了算汇率差和国内基础金价的浮动,预估的总价和实际付款差了快1800࿰…...
汤姆供应链
1. 自营中泰专线渠道,泰国曼谷设有清关公司与海外仓,本地团队 24 小时响应;2. 与多家船公司签订特种柜舱位协议,旺季舱位有保障;3. 服务过机械制造、建材、跨境电商等行业客户,累计运输超 1000 票大件设备&…...
3个真实场景告诉你,Avogadro 2分子建模软件如何改变化学研究方式
3个真实场景告诉你,Avogadro 2分子建模软件如何改变化学研究方式 【免费下载链接】avogadroapp Avogadro is an advanced molecular editor designed for cross-platform use in computational chemistry, molecular modeling, bioinformatics, materials science, …...
自动售货机哪个品牌好?2026年选购避坑全攻略~YH
经常有朋友问我:“自动售货机到底选哪个牌子?”说实话,这个问题我之前也纠结过。市面上做自动售货机的品牌不下几十家,价格从几千到几万都有,广告一个比一个响。但真正用下来,才知道差别有多大。今天就把这…...
压接 vs 焊接:高速连接器组装工艺的选型指南与实战对比
摘要/前言在通信设备、工业控制及数据中心硬件设计中,连接器的组装工艺选择直接影响产品的可靠性、可维护性与生产良率。压接(Press-Fit)与焊接(Soldering)是当前通孔连接器最主要的两种电气互连方式。压接依靠过盈配合…...
通过 Taotoken CLI 工具一键配置开发环境中的多模型访问密钥
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 通过 Taotoken CLI 工具一键配置开发环境中的多模型访问密钥 在接入多个大模型服务时,开发者通常需要为不同的工具&…...
Cortex-M0中断与系统控制:从NVIC、SysTick到低功耗实战解析
1. 项目概述:从零开始理解Cortex-M0的中断与系统控制如果你正在接触基于ARM Cortex-M0内核的微控制器,比如STM32F0系列、NXP的LPC800系列,或者是一些国产的M0芯片,那么“中断”和“系统控制”这两个词,绝对是你绕不开的…...
10大好用WMS系统盘点!2026年企业WMS系统选型实战指南
在2026年企业数字化转型的浪潮中,WMS系统(仓储管理系统)已经成为提升供应链效率的核心工具。面对市面上琳琅满目的WMS系统,企业如何进行精准的WMS系统选型,成为了管理者面临的一大难题。为了帮助大家避坑,本…...
当你的BERT模型被‘下毒’了怎么办?聊聊NLP后门攻击的实战检测与防御(附ONION、T-Miner工具实操)
当BERT模型遭遇后门攻击:一线工程师的检测与防御实战指南 在部署基于BERT的文本分类服务时,许多团队会忽略一个潜在威胁——模型可能已在训练阶段被植入后门。这类攻击极其隐蔽:模型对正常输入表现完美,但当遇到特定触发词&#x…...
