深入浅出 RabbitMQ-消息可靠性投递

大家好,我是工藤学编程 🦉一个正在努力学习的小博主,期待你的关注
实战代码系列最新文章😉C++实现图书管理系统(Qt C++ GUI界面版)
SpringBoot实战系列🐷【SpringBoot实战系列】SpringBoot3.X 整合 MinIO 存储原生方案
分库分表分库分表之实战-sharding-JDBC分库分表执行流程原理剖析
消息队列深入浅出 RabbitMQ - SpringBoot2.X整合RabbitMQ实战

前情摘要:

1、深入浅出 RabbitMQ-核心概念介绍与容器化部署
2、深入浅出 RabbitMQ-简单队列实战
3、深入浅出 RabbitMQ-工作队列实战(轮训策略VS公平策略)
4、深入浅出 RabbitMQ-交换机详解与发布订阅模型实战
4、深入浅出 RabbitMQ-路由模式详解
5、深入浅出 RabbitMQ - 主题模式(Topic)
6、深入浅出 RabbitMQ - SpringBoot2.X整合RabbitMQ实战

本文章目录

  • 深入浅出 RabbitMQ-消息可靠性投递
    • 一、什么是消息可靠性投递?
    • 二、RabbitMQ消息投递路径与关键控制点
    • 三、可靠性投递核心机制
      • 1. 生产者到交换机:ConfirmCallback机制
        • 配置方式(SpringBoot环境):
        • 实战代码:
        • 异常模拟:
      • 2. 交换机到队列:ReturnCallback机制
        • 配置方式:
        • 实战代码:
    • 四、注意事项:可靠性与性能的权衡
    • 总结

深入浅出 RabbitMQ-消息可靠性投递

在分布式系统中,消息队列作为解耦服务、削峰填谷的核心组件,其消息传递的可靠性直接影响业务稳定性。想象一下,电商订单支付后因消息丢失导致物流系统未触发发货,这样的问题足以让用户流失。今天我们就深入探讨RabbitMQ如何实现消息的可靠性投递,从底层原理到实战代码一网打尽。

一、什么是消息可靠性投递?

消息可靠性投递指的是确保消息从生产者发送到消费者的全链路过程中不丢失,具体包含三层含义:

  1. 消息百分百到达消息队列(避免网络波动导致的丢失)
  2. 消息队列节点成功接收并持久化消息(防止节点宕机丢失)
  3. 生产者能明确感知消息发送状态,对失败消息有完善的补偿机制(重试、存储等)

二、RabbitMQ消息投递路径与关键控制点

RabbitMQ的消息投递路径是:生产者 → 交换机(Exchange)→ 队列(Queue)→ 消费者

在这条路径上,有两个最容易发生消息丢失的节点,也是我们需要重点控制的环节:

  • 生产者到交换机的投递过程
  • 交换机到队列的路由过程

“为什么消息进入队列后,相对不容易发生丢失?” 或者 “为什么队列到消费者的环节相对不容易丢失消息?”,可以从 RabbitMQ 的设计机制来解释:

  1. 队列本身的存储特性保障了消息的稳定性
    消息进入队列后,RabbitMQ 会将消息存储在磁盘(持久化配置下)或内存中,队列的设计天然具备抗丢失能力:
    持久化机制:如果队列声明时设置了durable=true(持久化队列),且消息发送时设置了deliveryMode=2(持久化消息),那么消息会被写入磁盘。即使 RabbitMQ 节点宕机重启,队列和消息也能从磁盘恢复,避免了内存数据丢失的风险。
    镜像队列:在集群环境中,队列可以配置为 “镜像队列”(Mirror Queue),消息会同步到多个节点的副本中。即使主节点故障,从节点也能接管,避免单节点故障导致的消息丢失。
  2. 队列到消费者的投递机制有明确的确认机制
    消息从队列投递到消费者时,RabbitMQ 通过消费者确认机制(Ack) 确保消息被正确处理,避免丢失:
    消费者默认需要显式发送ack(确认)信号:当消费者处理完消息后,必须手动发送确认(channel.basicAck()),队列才会删除该消息。
    若消费者未确认且断开连接(如崩溃),队列会将消息重新投递:这种 “未确认则重发” 的机制,确保了消费者未处理成功的消息不会被丢弃。
    可以设置autoAck=false(关闭自动确认):避免消费者还没处理完消息就自动确认,导致处理失败后消息丢失。
  3. 队列到生产者的 “回退” 是异常场景,且有明确触发条件
    只有在交换机到队列路由失败时(如路由键不匹配、队列不存在),且开启了mandatory=true,消息才会通过ReturnCallback回退给生产者。这种场景下:
    回退的是 “未成功路由到队列的消息”,本质是 “交换机到队列” 环节的失败处理,而非正常的 “队列到生产者” 流程。
    此时消息并未进入队列,所以不存在 “队列存储后再丢失” 的问题 —— 因为消息根本没被队列接收,直接被回退了。

三、可靠性投递核心机制

1. 生产者到交换机:ConfirmCallback机制

当生产者发送消息后,RabbitMQ的Broker节点收到消息会返回一个ACK确认信号。通过ConfirmCallback回调,生产者可以明确知道消息是否成功到达交换机,这是可靠性投递的核心机制。

配置方式(SpringBoot环境):
# 新版配置(推荐)
spring.rabbitmq.publisher-confirm-type: correlated  # 消息到达交换机后触发回调
# 旧版配置(已过时)
# spring.rabbitmq.publisher-confirms: true
实战代码:
@Autowired
private RabbitTemplate rabbitTemplate;@Test
void testConfirmCallback() {// 设置确认回调rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {System.out.println("=====ConfirmCallback触发====");System.out.println("消息是否到达交换机:" + (ack ? "成功" : "失败"));System.out.println("失败原因:" + cause);// 业务处理:失败时可记录日志、执行重试或存入本地消息表if (!ack) {log.error("消息发送失败,准备重试: {}", correlationData.getId());// retryLogic(correlationData);}});// 发送消息CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString()); // 消息唯一标识rabbitTemplate.convertAndSend("order.exchange",  // 交换机名称"order.new",       // 路由键"新订单创建:ID=1001",  // 消息内容correlationData);
}
异常模拟:

若故意修改交换机名称为不存在的"invalid.exchange",回调会收到ack=false,并返回"channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no exchange ‘invalid.exchange’ in vhost ‘/’, class-id=60, method-id=40)"的错误原因。

2. 交换机到队列:ReturnCallback机制

消息成功到达交换机后,若因路由键错误、队列不存在等原因导致无法路由到队列,默认情况下消息会被直接丢弃。ReturnCallback机制可以捕获这类路由失败的消息,让生产者有机会处理。

配置方式:
spring.rabbitmq.publisher-returns: true  # 开启返回回调
spring.rabbitmq.template.mandatory: true  # 强制要求路由失败时返回消息
实战代码:
@Test
void testReturnCallback() {// 设置返回回调rabbitTemplate.setReturnsCallback(returnedMessage -> {System.out.println("=====ReturnCallback触发====");System.out.println("状态码:" + returnedMessage.getReplyCode());System.out.println("路由失败原因:" + returnedMessage.getReplyText());System.out.println("交换机:" + returnedMessage.getExchange());System.out.println("路由键:" + returnedMessage.getRoutingKey());System.out.println("消息内容:" + new String(returnedMessage.getMessage().getBody()));// 业务处理:可记录失败消息,人工介入或重新投递});// 发送消息(故意使用错误路由键)rabbitTemplate.convertAndSend("order.exchange","invalid.key",  // 不存在的路由键"新订单创建:ID=1002");
}

四、注意事项:可靠性与性能的权衡

开启Confirm和Return机制后,每一条消息都会增加一次网络交互(Broker返回确认),这会导致:

  • RabbitMQ整体吞吐量下降约30%-50%
  • 生产者处理链路变长,增加响应时间

因此,非核心业务消息不建议开启(如日志收集、非关键通知)。对于核心业务(订单、支付),可结合本地消息表实现最终一致性:

  1. 发送消息前先存入数据库(状态:待发送)
  2. 收到ConfirmCallback成功确认后更新状态(状态:已发送)
  3. 定期扫描未确认消息,执行重试

总结

RabbitMQ的消息可靠性投递通过两大回调机制实现:

  • ConfirmCallback:确保消息到达交换机
  • ReturnCallback:确保消息从交换机路由到队列

在实际应用中,需根据业务重要性权衡可靠性与性能,核心场景建议结合本地消息表做补偿,非核心场景可适当放宽策略。

掌握这些机制,就能在分布式系统中构建起可靠的消息传递链路,为业务稳定性保驾护航。

觉得有用请点赞收藏!
如果有相关问题,欢迎评论区留言讨论~

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

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

相关文章

数字化时代,中小企业如何落地数字化转型

大数据时代&#xff0c;各行各业的行业龙头和大型集团都已经开始了数据管理&#xff0c;让数据成为数据资产。但是在我国&#xff0c;中小企业的数量巨大&#xff0c;很多管理者忽视了这一点&#xff0c;今天我们就来聊一聊中小企业的数字化转型。中小企业需要数字化转型首先要…

Unity笔记(九)——画线功能Linerenderer、范围检测、射线检测

写在前面&#xff1a;写本系列(自用)的目的是回顾已经学过的知识、记录新学习的知识或是记录心得理解&#xff0c;方便自己以后快速复习&#xff0c;减少遗忘。这里只记录代码知识。十一、画线功能Linerenderer画线功能Linerenderer是Unity提供的画线脚本&#xff0c;创建一个空…

刷题记录(8)string类操作使用

一、仅反转字母 917. 仅仅反转字母 - 力扣&#xff08;LeetCode&#xff09; 简单来说输入字符串&#xff0c;要求你返回所有仅字母位置反转后的字符串。 简单看一个样例加深理解&#xff1a; 前后互换&#xff0c;我想思路基本很明显了&#xff0c;双指针&#xff0c;或者说…

用好AI,从提示词工程到上下文工程

前言 随着 AI 大模型的爆发,提示词工程(prompt engineering ) 一度是用户应用 AI ,发挥 AI 能力最重要、也最应该掌握的技术。 但现在,在 “提示词工程”的基础上,一个更宽泛也更强力的演化概念被提出,也就是本文我们要介绍的 “上下文工程(Context Engineering)” …

计算机Python毕业设计推荐:基于Django+Vue用户评论挖掘旅游系统

精彩专栏推荐订阅&#xff1a;在下方主页&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f496;&#x1f525;作者主页&#xff1a;计算机毕设木哥&#x1f525; &#x1f496; 文章目录 一、项目介绍二、…

⸢ 肆 ⸥ ⤳ 默认安全:安全建设方案 ➭ a.信息安全基线

&#x1f44d;点「赞」&#x1f4cc;收「藏」&#x1f440;关「注」&#x1f4ac;评「论」 在金融科技深度融合的背景下&#xff0c;信息安全已从单纯的技术攻防扩展至架构、合规、流程与创新的系统工程。作为一名从业十多年的老兵&#xff0c;将系统阐述数字银行安全体系的建设…

如何用AI视频增强清晰度软件解决画质模糊问题

在视频制作和分享过程中&#xff0c;画质模糊、细节丢失等问题常常影响观看体验。无论是老旧视频的修复还是低分辨率素材的优化&#xff0c;清晰度提升都成为用户关注的重点。借助专业的AI技术&#xff0c;这些问题可以得到有效解决。目前市面上存在多种解决方案&#xff0c;能…

Linux92 shell:倒计时,用户分类

问题 while IFS read -r line;doootweb kk]# tail -6 /etc/passwd user1r4:x:1040:1040::/home/user1r4:/bin/bash useros20:x:1041:1041::/home/useros20:/bin/bash useros21:x:1042:1042::/home/useros21:/bin/bash useros22:x:1043:1043::/home/useros22:/bin/bash useros23…

LinkedList源码解析

1. 数据结构设计 (1) 节点结构 LinkedList 的核心是双向链表节点 Node&#xff1a; private static class Node<E> {E item; // 存储的元素Node<E> next; // 后继节点Node<E> prev; // 前驱节点Node(Node<E> prev, E element, Node<E&g…

语雀批量导出知识库

使用工具&#xff1a;yuque-dl 参考文档&#xff1a; GitHub - gxr404/yuque-dl: yuque 语雀知识库下载 Yuque-DL&#xff1a;一款强大的语雀资源下载工具_语雀文档怎么下载-CSDN博客

电子电气架构 --- 当前企业EEA现状(下)

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…

flink中的窗口的介绍

本文重点 无界流会源源不断的产生数据,有的时候我们需要把无界流进行切分成一段一段的有界数据,把一段内的所有数据看成一个整体进行聚合计算,这是实现无界流转成有界流的方式之一。 为什么需要窗口 数据是源源不断产生的,我们可能只关心某个周期内的统计结果。比如电费…

自建es 通过Flink同步mysql数据 Docker Compose

资源es:7.18 kibana:7.18 flink:1.17.2目录mkdir -p /usr/project/flink/{conf,job,logs} chmod -R 777 /usr/project/flink #资源情况 mysql8.0 Elasticsearch7.18 自建# 目录结构 /usr/project/flink/ /usr/project/flink/ ├── conf/ │ ├── flink-conf.yaml │ └…

AI浏览器和钉钉ONE是不是伪需求?

最近两则新闻格外引起了我的注意&#xff1a;一是Claude推出了官方浏览器插件&#xff0c;二是钉钉发布了钉钉ONE。前者说明AI浏览器未必有必要&#xff0c;后者则描绘了一幅“刷刷手机就能完成工作”的未来办公图景。这几天我经常在思考&#xff0c;AI浏览器是不是没有必要&am…

从结构化到多模态:RAG文档解析工具选型全指南

在RAG系统建设中&#xff0c;文档解析质量直接决定最终效果上限&#xff0c;选择合适的解析工具已成为避免"垃圾进&#xff0c;垃圾出"&#xff08;GIGO&#xff09;困境的关键决策。一、文档解析&#xff1a;RAG系统的基石与瓶颈 当前企业知识库中超过80%的信息存储…

设计模式:享元模式(Flyweight Pattern)

文章目录一、享元模式的介绍二、实例分析三、示例代码一、享元模式的介绍 享元模式&#xff08;Flyweight Pattern&#xff09; 是一种结构型设计模式。通过共享相同对象&#xff0c;减少内存消耗&#xff0c;提高性能。 它摒弃了在每个对象中保存所有数据的方式&#xff0c; 通…

【Go语言入门教程】 Go语言的起源与技术特点:从诞生到现代编程利器(一)

文章目录前言1. Go语言的起源与发展2. Go语言的核心设计团队2.1 Ken Thompson&#xff08;肯汤普森&#xff09;2.2 Rob Pike&#xff08;罗布派克&#xff09;2.3 Robert Griesemer&#xff08;罗伯特格瑞泽默&#xff09;设计动机&#xff1a;解决C的痛点3. Go语言的核心特性…

rocketmq启动与测试

1.更改runserver.sh的内存大小 vi runserver.sh 2.更改 runbroker.sh内存大小 vi runbroker.sh3.设置环境变量 vi ~/.bash_profile 新增 export NAMESRV_ADDRlocalhost:98764.启动 --在bin的上一级目录启动 nohup bin/mqnamesrv & nohup bin/mqbroker &5.查看日志 le…

11.《简单的路由重分布基础知识探秘》

11_路由重分布 文章目录11_路由重分布路由重分布概述路由重分布的核心作用基础实验实验流程实验拓扑配置示例(基本操作省略)实验结论路由重分布概述 路由重分布&#xff08;又称路由引入&#xff09;是指在不同路由协议之间交换路由信息的技术。在复杂网络中&#xff0c;可能同…

C++ 左值引用与右值引用介绍

C 左值引用与右值引用详解 在 C 的类型系统中&#xff0c;引用&#xff08;reference&#xff09; 是一种为已有对象起别名的机制。在早期&#xff08;C98/03&#xff09;中&#xff0c;C 只有 左值引用&#xff08;lvalue reference&#xff09;&#xff0c;主要用于函数参数…