1. 消息确认机制(ack)

RabbitMQ 消息投递到消费者后,必须确认(ack)才能从队列中移除:

  • auto-ack = true

    • 消息一投递就算消费成功。

    • 如果消费者宕机,消息会丢失。

    • 一般不用。

  • manual-ack = false(默认)

    • 由 Spring AMQP 或手动调用 basicAck 来确认。

    • 消费成功 → basicAck

    • 消费失败 → basicNackbasicReject

    • 是否重回队列取决于 requeue 参数。


2. Spring Retry 机制

捕获位置

  • Spring Retry 通过 AOP 代理在方法外部包裹一个“重试拦截器”

  • 异常必须从方法栈顶抛出到代理外层才能被捕获

  • 方法内部 try-catch 捕获的异常 不会冒泡到代理外层 → Retry 无法捕获

如何才能触发

  • 必须在 @RabbitListener 方法上出现异常并且不处理,Spring Retry 才能捕获并重试

  • 方法内部捕获异常或自己处理掉 → Retry 无法触发

Spring Boot 已内置 RetryTemplate,只要配置就能在消费者异常时自动重试。

配置示例(application.yml)

 acknowledge-mode: auto --》消息会在消费者方法执行完毕后被自动确认(ACK)

spring:rabbitmq:listener:simple:acknowledge-mode: auto# 一般用自动ack 消息会在消费者方法执行完毕后被自动确认(ACK)retry:enabled: true            # 开启消费者重试max-attempts: 5          # 最大重试次数initial-interval: 1000   # 第一次重试间隔 1smultiplier: 2.0          # 重试间隔倍数(指数退避)max-interval: 10000      # 最大重试间隔 10s

消费者示例

@Component
public class RetryConsumer {@RabbitListener(queues = "test.retry.queue")public void onMessage(String msg) {System.out.println("收到消息:" + msg);// 模拟业务异常if (msg.contains("error")) {throw new RuntimeException("消费失败,触发Spring Retry");}System.out.println("消费成功:" + msg);}
}

执行流程

  1. 第一次失败 → 等待 1s 后再次执行。

  2. 第二次失败 → 等待 2s 后再次执行。

  3. 第三次失败 → 等待 4s 后再次执行。

  4. …直到 max-attempts 用完。

  5. 超过最大次数 → 调用 RecoveryCallback(默认是丢弃或进入 DLQ)。

👉 注意:Spring Retry 只在 消费者方法抛异常 时才会触发。如果内部用try-catch处理了没有抛出则不会触发Spring Retry
👉 这里也可以把重试几次看做重复消费几次,以及重试的话也会多次执行相同的业务代码


3. 手动 Nack + DLQ(推荐生产场景)

有时我们不想依赖 Spring Retry,而是用 手动 nack 配合 死信队列(DLQ) 遇到异常如何处理。

配置队列(带 DLQ)

@Configuration
public class RabbitConfig {@Beanpublic Queue businessQueue() {return QueueBuilder.durable("test.dlx.queue").withArgument("x-dead-letter-exchange", "dlx.exchange") // 绑定死信交换机.withArgument("x-dead-letter-routing-key", "dlx.key").build();}@Beanpublic DirectExchange dlxExchange() {return new DirectExchange("dlx.exchange");}@Beanpublic Queue deadLetterQueue() {return new Queue("dlx.queue");}@Beanpublic Binding bindingDLQ() {return BindingBuilder.bind(deadLetterQueue()).to(dlxExchange()).with("dlx.key");}
}

消费者(手动控制 ack/nack)

@Component
public class DLQConsumer {@RabbitListener(queues = "test.dlx.queue")public void onMessage(String msg, Channel channel, Message message) throws IOException {try {System.out.println("收到消息:" + msg);if (msg.contains("error")) {throw new RuntimeException("消费失败,进入DLQ");}// 成功手动确认channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);} catch (Exception e) {System.err.println("消费异常:" + e.getMessage());// 失败:不重回队列,直接进入 DLQchannel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);}}
}

这里就算在yml中定义重试也没有作用,原因如下:

  1. Spring Retry 的工作时机

    • 当你配置了 retry: enabled: true 时,Spring会创建一个代理(AOP Around Advice)来包裹你的 @RabbitListener 方法。

    • 这个代理的逻辑是:当你的监听方法抛出异常,它才会捕获这个异常,并根据配置进行重试(等待间隔、重试次数等)。

    • 在所有重试次数用尽后,如果仍然失败,这个代理会抛出一个 AmqpRejectAndDontRequeueException 异常,这会触发RabbitMQ将消息拒绝并送入死信队列(DLQ)。

  2. 你的代码做了什么

    • 你在方法内部使用了 try-catch捕获了所有异常(Exception e

    • 在 catch 块中,你直接调用了 channel.basicNack(...) 手动拒绝了消息。

    • 关键点:由于异常被你亲手捕获并处理了,它并没有被抛出到方法之外。因此,外层的Spring Retry代理根本看不到任何异常,它认为本次消费已经“成功”处理完毕(尽管是手动Nack了),所以重试机制完全没有机会触发。


4. 对比总结

方案原理配置复杂度重试策略消息去向适用场景
Spring RetrySpring AMQP 捕获异常,内部调度重试简单(yml 配置即可)指数退避/固定间隔超过次数 → 默认丢弃或进入 DLQ开发测试、简单重试需求
手动 Nack + DLQ消费失败 → basicNack(requeue=false) → 死信队列 → 再投递较复杂(需要DLQ配置)由 TTL + DLQ 控制(灵活)失败消息进入 DLQ,便于监控和人工处理生产环境,严格保证消息不丢失

5. 推荐做法(生产级)

  1. 不要依赖 auto-ack,统一用 manual-ack

  2. 开发阶段 → 可以用 Spring Retry 简单实现。

  3. 生产环境 → 建议用 DLQ + TTL 延时重试,可控性强,防止消息丢失。

  4. 关键业务 → 搭配消息追踪 & 异常告警。

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

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

相关文章

eniac:世界上第一台通用电子计算机的传奇

本文由「大千AI助手」原创发布,专注用真话讲AI,回归技术本质。拒绝神话或妖魔化。搜索「大千AI助手」关注我,一起撕掉过度包装,学习真实的AI技术! ✨ 1. eniac概述:计算机时代的黎明 eniac(ele…

网络与信息安全有哪些岗位:(6)安全开发工程师

想知道网络与信息安全领域有哪些具体岗位吗? 网络与信息安全有哪些岗位:(1)网络安全工程师-CSDN博客 网络与信息安全有哪些岗位:(2)渗透测试工程师_网络安全渗透工程师-CSDN博客 网络与信息安…

C-JSON接口的使用

一、cJSON 核心数据结构cJSON 的所有操作都围绕 cJSON 结构体展开,它代表 JSON 中的一个节点(可以是对象、数组、字符串、数字等):typedef struct cJSON {struct cJSON *next, *prev; // 用于链表(数组/对象的子节点…

TypeScript 类型系统(二)

本文将简述类型系统中的类型联合,通俗的来说就是将一个变量规定为不是某一个类型,而是某些类型,我们在日常开发中很常见下面会给出例子。值类型在JavaScript中用const声明的变量是不可以再次赋值的,也就是常量。在TypeScript中也可…

无刷电机控制 - STM32F405+CubeMX+HAL库+SimpleFOC08,速度闭环控制(有电流环)

导言 《STM32F405CubeMXHAL库SimpleFOC07,ADC采样相电流,频率20KHz(TIM1触发Injected Sampling中断》,有了上一章节的电流采样后,可以完善速度闭环控制了。 有了电流环的速度闭环控制,电机的扭矩会显得大很…

【机械故障】共振峰

机械故障信号分析 提示:学习笔记 1、机械振动名词 2、共振峰 共振峰 机械故障信号分析 1、机械振动名词 [2、共振峰](https://editor.csdn.net/md/?not_checkout=1&activity_id=10937&spm=1057.2600.3001.10415) @[TOC](共振峰) `详细讲解共振峰、共振频率带、共振频…

力扣(用队列实现栈)

解析 LeetCode 225. 用队列实现栈:单队列的巧妙运用 一、题目分析(一)功能需求 实现 MyStack 类,支持栈的四种操作: push(int x):将元素压入栈顶。pop():移除并返回栈顶元素。top():…

服务器Docker 安装和常用命令总结

Docker 安装和常用命令总结Docker 是一种开源平台,用于自动化应用程序的部署、扩展和管理。通过将应用程序及其依赖打包到一个轻量级、可移植的容器中,Docker 能够在任何地方统一运行,解决了不同环境间的兼容性问题。本篇文章将介绍 Docker 的…

2025年广东省无线电管理普法宣传活动

一、无线电发射设备型号核准相关制度及要求1.型号核准设备类型:一、公众网移动通信设备二、专用通信设备三、无线接入设备四、广播发射设备五、雷达设备六、导航设备七、卫星通信设备(含终端地球站)无线电发射设备八、公众网移动通信模块九、无线接入模块十、其他设…

使用 Whisper 将南蒂罗尔方言语音转录为标准德语文本的研究

使用 Whisper 将南蒂罗尔方言语音转录为标准德语文本的研究 原文:Speech transcription from South Tyrolean Dialect to Standard German with Whisper 本研究展示了首个经过微调的Whisper模型,用于将南蒂罗尔方言语音自动翻译为标准德语文本。为了满足字幕和翻译方面尚未被…

Nexus管理maven仓库和jar包的配置和使用

登录nexus以后点击Settings-Repository-Repositories-Create repository 选择maven2(hosted)创建两个仓库一个是Release叫做monitor-releases:一个是Snapshot叫做monitor-snapshots:在创建一个maven2(group)叫做monitor将maven-central(用于存…

疯狂星期四文案网第50天运营日记

网站运营第50天,点击观站: 疯狂星期四 crazy-thursday.com 全网最全的疯狂星期四文案网站 运营报告 今日访问量 今天流量减了一些,我发现我的疯狂星期四的词没有排名第一了,感觉应该是抽象文案这个导致的,因为我发了…

计算机视觉学习路线:从入门到进阶的完整指南

计算机视觉学习路线:从入门到进阶的完整指南 计算机视觉(Computer Vision, CV)是人工智能领域最热门和最具前景的方向之一,它赋予机器“看”和“理解”图像与视频的能力。无论你是学生、工程师还是对AI感兴趣的爱好者&#xff0c…

移动应用抓包与调试实战 Charles工具在iOS和Android中的应用

随着移动互联网的发展,几乎所有应用都依赖API接口进行数据交互。无论是登录注册、支付功能,还是新闻资讯加载,背后都需要与服务器频繁通信。如何快速定位问题、验证数据传输、模拟弱网环境,成为移动端开发者日常工作中的关键任务。…

【Python NTLK自然语言处理库】

安装流程 import nltk nltk.download()运行后出现一个界面,然后按DownloadTokenize ###分词 from nltk.tokenize import word_tokenize text "The vendor paid $20,000,000." tokens word_tokenize(text) print(tokens)输出 [The, vendor, paid, $, 20,…

GitHub 热榜项目 - 日榜(2025-08-25)

GitHub 热榜项目 - 日榜(2025-08-25) 生成于:2025-08-25 统计摘要 共发现热门项目:20 个 榜单类型:日榜 本期热点趋势总结 本期GitHub热榜呈现三大技术趋势:1)AI代理开发成主流,如moeru-ai/airi的虚拟伴…

Mac相册重复照片终结指南:技术流清理方案

你的Mac相册是否变成了"重复照片博物馆"?同一场景的多个版本、连续拍摄的相似图片、不同设备导入的重复文件...这些数字冗余正在悄无声息地吞噬着宝贵的存储空间。本文将为你提供一套完整的技术解决方案。重复照片问题的技术分析重复类型分类从技术角度&a…

日语学习-日语知识点小记-构建基础-JLPT-N3阶段(19):文法复习+单词第7回1

日语学习-日语知识点小记-构建基础-JLPT-N3阶段(19):文法单词第7回1 1、前言(1)情况说明(2)工程师的信仰2、知识点1ー 復習3、单词(1)日语单词  …

完美世界招数据仓库工程师咯

数据仓库工程师-偏BI方向 (岗位信息经过jobleap.cn授权,可在CSDN发布)完美世界 北京 职位描述 负责数据仓库架构设计、建模和ETL开发,构建可扩展的数据仓库和分析解决方案; 负责对数据仓库的性能和效率优化&#xff1…