腾讯二面:引入RabbitMQ后,你如何保证全链路数据100%不丢失 ?

RabbitMQ 从入门到生产实践:核心概念、部署配置与高可用架构详解 消息队列是分布式系统和微服务架构中实现异步通信、系统解耦和流量削峰的核心组件。其基本原理是通过生产者-消费者模型,将消息暂存于队列中,实现服务间的可靠、异步数据传递。这一技术能有效提升系统弹性、吞吐量和可维护性,是构建高并发、高可用应用的关键基础设施。在实际应用中,RabbitMQ 作为实现了 AMQP 协议的企业级消息代理,凭借其成熟稳定的特性、友好的管理界面和丰富的客户端支持,成为众多团队在实现服务解耦、异步任务处理(如订单超时取消)和流量洪峰应对时的首选方案。本文将从 RabbitMQ 的核心概念与工 阅读详情

原文:blog.youkuaiyun.com/hsz2568952354/article/details/86559470

我们都知道,消息从生产端到消费端消费要经过3个步骤:

  1. 生产端发送消息到RabbitMQ;

  2. RabbitMQ发送消息到消费端;

  3. 消费端消费这条消息;

dd783b13b923d9ebea19614ae6210d6a.png

这3个步骤中的每一步都有可能导致消息丢失,消息丢失不可怕,可怕的是丢失了我们还不知道,所以要有一些措施来保证系统的可靠性。

这里的可靠并不是一定就100%不丢失了,磁盘损坏,机房爆炸等等都能导致数据丢失,当然这种都是极小概率发生,能做到99.999999%消息不丢失,就是可靠的了。下面来具体分析一下问题以及解决方案。

生产端可靠性投递

生产端可靠性投递,即生产端要确保将消息正确投递到RabbitMQ中。

生产端投递的消息丢失的原因有很多,比如消息在网络传输的过程中发生网络故障消息丢失,或者消息投递到RabbitMQ时RabbitMQ挂了,那消息也可能丢失,而我们根本不知道发生了什么。

针对以上情况,RabbitMQ本身提供了一些机制。

事务消息机制

事务消息机制由于会严重降低性能,所以一般不采用这种方法,我就不介绍了,而采用另一种轻量级的解决方案:confirm消息确认机制。

confirm消息确认机制

什么是confirm消息确认机制?顾名思义,就是生产端投递的消息一旦投递到RabbitMQ后,RabbitMQ就会发送一个确认消息给生产端,让生产端知道我已经收到消息了,否则这条消息就可能已经丢失了,需要生产端重新发送消息了。

747907eab285c5c06a079307f4c75627.png

通过下面这句代码来开启确认模式:

channel.confirmSelect();// 开启发送方确认模式

然后异步监听确认和未确认的消息:

channel.addConfirmListener(new ConfirmListener() {
    //消息正确到达broker
    @Override
    public void handleAck(long deliveryTag, boolean multiple) throws IOException {
        System.out.println("已收到消息");
        //做一些其他处理
    }

    //RabbitMQ因为自身内部错误导致消息丢失,就会发送一条nack消息
    @Override
    public void handleNack(long deliveryTag, boolean multiple) throws IOException {
        System.out.println("未确认消息,标识:" + deliveryTag);
        //做一些其他处理,比如消息重发等
    }
});

这样就可以让生产端感知到消息是否投递到RabbitMQ中了,当然这样还不够,稍后我会说一下极端情况。

消息持久化

那消息持久化呢?我们知道,RabbitMQ收到消息后将这个消息暂时存在了内存中,那这就会有个问题,如果RabbitMQ挂了,那重启后数据就丢失了,所以相关的数据应该持久化到硬盘中,这样就算RabbitMQ重启后也可以到硬盘中取数据恢复。那如何持久化呢?

message消息到达RabbitMQ后先是到exchange交换机中,然后路由给queue队列,最后发送给消费端。

7bfb8404cea0a8f1a77980a794994f07.png

所有需要给exchange、queue和message都进行持久化:

exchange持久化:

//第三个参数true表示这个exchange持久化
channel.exchangeDeclare(EXCHANGE_NAME, "direct", true);

queue持久化:

//第二个参数true表示这个queue持久化
channel.queueDeclare(QUEUE_NAME, true, false, false, null);

message持久化:

//第三个参数MessageProperties.PERSISTENT_TEXT_PLAIN表示这条消息持久化
channel.basicPublish(EXCHANGE_NAME, ROUTING_KEY, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes(StandardCharsets.UTF_8));

这样,如果RabbitMQ收到消息后挂了,重启后会自行恢复消息。

到此,RabbitMQ提供的几种机制都介绍完了,但这样还不足以保证消息可靠性投递RabbitMQ中,上面我也提到了会有极端情况,比如RabbitMQ收到消息还没来得及将消息持久化到硬盘时,RabbitMQ挂了,这样消息还是丢失了,或者RabbitMQ在发送确认消息给生产端的过程中,由于网络故障而导致生产端没有收到确认消息,这样生产端就不知道RabbitMQ到底有没有收到消息,就不好做接下来的处理。

810b9a0d75be467bfdbf4f55b976fa90.png

所以除了RabbitMQ提供的一些机制外,我们自己也要做一些消息补偿机制,以应对一些极端情况。接下来我就介绍其中的一种解决方案——消息入库。

消息入库

消息入库,顾名思义就是将要发送的消息保存到数据库中。

首先发送消息前先将消息保存到数据库中,有一个状态字段status=0,表示生产端将消息发送给了RabbitMQ但还没收到确认。在生产端收到确认后将status设为1,表示RabbitMQ已收到消息。

这里有可能会出现上面说的两种情况,所以生产端这边开一个定时器,定时检索消息表,将status=0并且超过固定时间后(可能消息刚发出去还没来得及确认这边定时器刚好检索到这条status=0的消息,所以给个时间)还没收到确认的消息取出重发(第二种情况下这里会造成消息重复,消费者端要做幂等性),可能重发还会失败,所以可以做一个最大重发次数,超过就做另外的处理。

d1930778c85c98bbae7cbd3fcf4113bc.png

这样消息就可以可靠性投递到RabbitMQ中了,而生产端也可以感知到了。

消费端消息不丢失

既然已经可以让生产端100%可靠性投递到RabbitMQ了,那接下来就改看看消费端的了,如何让消费端不丢失消息。

默认情况下,以下3种情况会导致消息丢失:

  • 在RabbitMQ将消息发出后,消费端还没接收到消息之前,发生网络故障,消费端与RabbitMQ断开连接,此时消息会丢失;

  • 在RabbitMQ将消息发出后,消费端还没接收到消息之前,消费端挂了,此时消息会丢失;

  • 消费端正确接收到消息,但在处理消息的过程中发生异常或宕机了,消息也会丢失。

1b7c1abdd41ddc859cf17bcf50b63fed.png

其实,上述3中情况导致消息丢失归根结底是因为RabbitMQ的自动ack机制,即默认RabbitMQ在消息发出后就立即将这条消息删除,而不管消费端是否接收到,是否处理完,导致消费端消息丢失时RabbitMQ自己又没有这条消息了。

a59942337ba54cc5e64ee7fcb8a23fd1.png

所以就需要将自动ack机制改为手动ack机制。

消费端手动确认消息:

DeliverCallback deliverCallback = (consumerTag, delivery) -> {
    try {
        //接收到消息,做处理
        //手动确认
        channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
    } catch (Exception e) {
        //出错处理,这里可以让消息重回队列重新发送或直接丢弃消息
    }
};
//第二个参数autoAck设为false表示关闭自动确认机制,需手动确认
channel.basicConsume(QUEUE_NAME, false, deliverCallback, consumerTag -> {});

这样,当autoAck参数置为false,对于RabbitMQ服务端而言,队列中的消息分成了两个部分:

  • 一部分是等待投递给消费端的消息;

  • 一部分是已经投递给消费端,但是还没有收到消费端确认信号的消息。

如果RabbitMQ一直没有收到消费端的确认信号,并且消费此消息的消费端已经断开连接或宕机(RabbitMQ会自己感知到),则RabbitMQ会安排该消息重新进入队列(放在队列头部),等待投递给下一个消费者,当然也有能还是原来的那个消费端,当然消费端也需要确保幂等性。

好了,到此从生产端到RabbitMQ再到消费端的全链路,就可以保证数据的不丢失。

腾讯云TDMQ消息队列选型、配置与生产环境实战指南 消息队列作为分布式系统异步解耦、削峰填谷的核心组件,其核心原理在于通过生产者-消费者模型,实现应用间的可靠通信与流量缓冲。这项技术对于构建高并发、可扩展的微服务架构具有关键价值,广泛应用于电商订单处理、实时日志流、金融交易等场景。本文聚焦于腾讯云TDMQ这一企业级消息中间件服务,深入解析其产品家族(包括TDMQ for RocketMQ、Pulsar等)的差异与选型策略,并结合生产环境中的**消息堆积**监控与**消费线程**配置等核心实践,提供从架构设计到性能调优的一站式解决方案,帮助开发者规避常见陷阱, 阅读详情

相关推荐

企业级音频格式转换:授权合规、加密解密与自动化架构实战

音频格式转换是多媒体处理中的基础技术,其核心原理是通过编解码器对音频数据进行压缩与重构,以适配不同播放场景。在技术价值层面,它直接关系到用户体验的一致性与数据分发的效率。然而,在企业级应用场景中,这项基础任务会面临复杂挑战:必须严格遵循软件授权合规,避免陷入开源协议或专利侵权风险;同时,需处理传输层与存储层的加密数据,在保障安全的前提下完成解码与转码。这自然引出了对自动化、高可靠处理流水线的需求。本文深入探讨了如何构建一个兼顾安全与效率的解决方案,其中涉及密钥管理服务与工作流自动化引擎等关键组件,为企业处理

weixin_30652897的博客 436

如何保证RabbitMQ全链路数据100%不丢失

这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 欢迎使用Ma...

指尖凉的博客 8054

卷积神经网络-猫狗识别(附源码)

利用python实现一个卷积神经网络,训练猫狗数据集,实现对猫狗图片的预测识别

m0_63223213的博客 2万+

面试官:引入RabbitMQ后,你如何保证全链路数据100%不丢失?

来源:blog.youkuaiyun.com/hsz2568952354/article/details/86559470生产端可靠性投递事务消息机制confirm消息确认机制消息持久化消息入库消费端消息不丢失我们都知道,消息从生产端到消费端消费要经过3个步骤:生产端发送消息到RabbitMQ;RabbitMQ发送消息到消费端;消费端消费这条消息;这3个步骤中的每一步都有可能导致消息...

HollisChuang's Blog 532

excel 利用SUBTOTAL函数计算筛选后数列总和、均值、最大、最小值

表里有三个人,咱们需要筛选出三个人,并分别计算他们的总和值。 先看一下数据范围(A1:B27) 通过筛选找张三。 按照上图所示输入函数,选择9,求和。 然后按照函数输入即可。 就能计算出结果。 筛选项选择王五,就会自动计算王五的总和。 筛选到李四就会自动计算李四的总和。 如果把9改成1,就是自动计算筛选出来的均值结果,如下图所示。 如果改成4就是取筛选项的最大值,选择5就是取最小值。 ...

yuanYW7556的博客 3万+

电力现货市场出清机制解析:从理论到实践(附节点电价计算实例)

本文深入解析电力现货市场的核心出清机制,重点阐述了节点边际电价的计算原理与实践方法。通过对比系统边际电价、节点边际电价和分区边际电价三种模式,揭示了市场出清价格如何反映电力供需与网络阻塞。文章结合IEEE 30节点系统,提供了基于MATLAB和最优潮流模型的计算实例,详细展示了从构建模型到求解对偶变量以获取节点电价的全过程,为理解电力市场定价机制提供了从理论到实践的完整路径。

whisky的博客 758

第五篇 工程化与后端基础(金融AI Agent面试版)

文章摘要:本文聚焦AI应用开发的工程基础,重点讲解Redis、数据库和消息队列三大模块的核心应用。Redis在AI系统中承担会话状态缓存、LLM响应缓存、接口限流和分布式锁四大角色;数据库选型需根据场景选择MySQL、PostgreSQL等,并掌握索引优化技巧;消息队列解决异步执行、削峰填谷等问题,提供Redis Streams、RabbitMQ等选型建议。全文强调工程落地实践,覆盖面试常见考点,是AI开发岗的必背保底内容。

weixin_45526015的博客 269

python音频信号分析

声音以具有诸如频率、带宽、分贝等参数的音频信号的形式表示,典型的音频信号可以表示为幅度和时间的函数

MAY的博客 2789

7.用DockerCompose接入RabbitMQ实现异步推理

本文介绍如何用 Docker Compose 部署 RabbitMQ,结合 FastAPI 与 Worker 实现异步推理。通过消息队列解耦任务提交与执行,确保大文件、视频等耗时任务不阻塞 HTTP 请求。关键实践包括:使用小体积消息传递任务标识、启用持久化与确认机制、手动 ACK 防止丢失、配置重试与死信队列、保障幂等性,并通过 PostgreSQL 管理任务状态。强调异步系统需兼顾消息可靠性、结果可查与容错能力,为算法工程化落地提供完整链路参考。

像风一样自由的博客 394

HOPE:基于强化学习的混合策略路径规划器,适用于多样化停车场景

本文提出了一种混合策略路径规划器(HOPE),用于解决自动停车中的路径规划问题。HOPE结合了强化学习(RL)和Reeds-Shepp(RS)曲线,通过动作掩码机制引导RL智能体的探索,并利用Transformer融合环境感知信息与掩码。该方法在多样且复杂的停车场景中实现了超过97%的成功率,并通过真实实验验证了其泛化能力。此外,本文还提出了基于空间与障碍物分布的停车场景难度分级标准,进一步提升了训练与评估的效率。实验结果表明,HOPE在规划成功率和跨场景泛化能力上均优于传统的基于规则算法和朴素强化学习方法

weixin_42783201的博客 1466

APB Timer验证环境搭建——学习笔记(6)

(1)为RELOAD VALUE配置初始值32'h8000_0000,设定边界值32'h4000_0000,可以看到减到想要的边界值的时候,counter重新加载RELOAD VALUE,重新开始计数;这根线,统计等待到中断的次数,与理论值做。(2)设定Reload value。(1)由于counter。recount总共次数;

qq_41651535的博客 497

消息队列入门:RabbitMQ 与 Kafka 核心概念与运维要点

BIOS→GRUB→内核→systemd→target 全链路解读,root 密码忘了解锁、文件系统损坏修复、单用户模式与救援模式实战,服务器起不来时的救命指南。

2502_91473995的博客 410

rk3568 修改开机动画

bootanimation.zip是一个Android设备启动时播放的动画文件,它包含了一系列的图片和描述文件,用于描述动画的播放顺序和持续时间。

weixin_35723192的博客 2730

从0到1掌握Kafka与RabbitMQ在IM即时聊天中的

本文从理论出发,结合《Designing Data-Intensive Applications》一书的知识体系,通过实际代码演示了如何利用Kafka与RabbitMQ来支撑IM系统的不同模块。无论是私聊还是群聊场景都可以找到对应解决方案。接下来你可以尝试以下几个方向进行深入学习: 1. 实现多节点集群部署,并了解如何设置HA机制。2. 学习如何在Spring Boot等框架中整合这两种中间件。3. 探索使用Flink或Spark Streaming对接Kafka做实时分析。

qq_41106321的博客 213

数据分析案例-对某宝用户评论做情感分析

目录 原始数据 绘制词云图 情感分析 原始数据 原始数据为某宝一商品的用户评论数据 绘制词云图 # coding=utf-8 import jieba import re import wordcloud import imageio # 打开需要分析词频的文本 with open('淘宝评论3.0.txt', encoding='utf-8') as f: data = f.read() # 文本预处理 :去除一些无用的字符只提取出中文出来 new_data

m0_64336780的博客 1万+

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Docker Compose 模块化多环境配置规范指南:示例搭建RabbitMQ 4.4.0-management

本文介绍Docker Compose模块化多环境配置规范,以RabbitMQ 4.4.0-management为例,采用双层配置隔离:根目录.env管理全局变量(如环境、网络),服务私有.env定义版本、密码、端口等专属参数。通过环境目录物理隔离(dev/test/prod),实现配置与数据的可移植性与安全性,支持一键部署与迁移。

郝开的博客 99

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

RabbitMQ 消费端幂等:唯一索引、条件更新、Redis 去重三种方案的真实代价

MQ 只承诺至少投递一次,重复消息只能消费端自己吃掉。这篇对比唯一索引、条件更新、Redis 短路三种去重方案在 AI 任务场景下的实际代价,附三个踩过的坑。

zhangpan 252

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

上一篇: 面试官:为什么数据库连接很消耗资源,资源都消耗在哪里?
下一篇: 雷军做程序员时写的博客,真心强啊!
Java思维导图
博客等级 码龄10年 306粉丝 71原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值