RabbitMQ 如何保证消息不丢失?

news/2024/10/20 15:37:49/

为了保证消息在 RabbitMQ 中不丢失,必须从生产者、Exchange 路由、Broker 和消费者等多个方面采取有效措施。RabbitMQ 消息丢失的场景主要分为以下三种情况:生产者端、路由过程以及消费者端。

一、RabbitMQ 消息丢失的三种情况

在讨论如何保证消息不丢失之前,我们先来看看一条消息从生产到消费的完整流程:

  1. 生产者将消息发送到Exchange
  2. Exchange根据Routing Key将消息路由到Queue
  3. 消费者订阅Queue,从Queue中获取消息进行消费。
消息丢失可能发生在以下几个阶段:
  1. 生产者丢失消息:生产者在将消息发送到 Exchange 的过程中,由于网络问题或发送到不存在的 Exchange,导致消息丢失。

  2. 路由失败:消息发送到了 Exchange,但 Exchange 在根据 Routing Key 路由时没有找到对应的 Queue,导致消息没有进入任何 Queue,从而丢失。

  3. 消费者处理失败:消费者已经成功从 Queue 中获取了消息,但在处理过程中发生异常,消息未正确处理或确认(ACK),导致消息丢失。

其他情况:RabbitMQ 服务崩溃时的消息丢失

即便上述问题都解决了,如果 RabbitMQ 服务器宕机且消息未被持久化,服务重启后这些未持久化的消息仍会丢失。因此,消息的持久化也是关键一环。


二、RabbitMQ 消息丢失的解决方案

针对不同的丢失场景,RabbitMQ 提供了多种机制来解决这些问题:

2.1 针对生产者端消息丢失
问题:生产者发送消息到 Exchange 时,由于网络问题或目标 Exchange 不存在,导致消息丢失。

解决方案:
RabbitMQ 提供了两种方式来解决生产者端的消息丢失问题:事务机制和发布确认机制。

(1)事务机制(不推荐,性能较差)

生产者可以在发送消息之前开启 RabbitMQ 事务,通过以下步骤确保消息不会丢失:

  1. 开启事务:channel.txSelect()
  2. 发送消息:channel.basicPublish()
  3. 如果发送成功,提交事务:channel.txCommit();否则,回滚事务:channel.txRollback(),并重试发送。

事务机制虽然可以确保消息可靠性,但由于性能问题不适合高并发场景。

(2)发布确认机制(推荐)

发布确认机制是一种更高效的方案,生产者在发送消息后可以收到 RabbitMQ 的确认(ACK)或否定确认(NACK)。步骤如下:

  1. 开启发布确认模式:channel.confirmSelect()
  2. 监听确认回调:
    • onAck():消息成功发送到 Broker。
    • onNack():消息发送失败,生产者可以选择重新发送。

发布确认模式不仅能够保证消息不会丢失,而且性能较事务模式要高得多,是生产环境中首选的方案。


2.2 针对路由失败
问题:消息到达了 Exchange,但由于没有合适的 Queue 路由,消息丢失。

解决方案:
通过配置 RabbitMQ 的备份交换机(Alternate Exchange,AE)和Mandatory 参数来处理消息的路由失败问题。

(1)Mandatory 参数

设置 mandatory=true,如果消息无法路由到任何 Queue,RabbitMQ 会将消息返回给生产者,生产者可以选择处理返回的消息或进行重试。

channel.basicPublish(exchange, routingKey, true, null, message);

 

(2)备份交换机(AE)

备份交换机是当消息未成功路由到 Queue 时,将消息路由到一个备用的 Exchange,确保消息不会丢失。例如,某些高优先级的消息可以转到备份交换机做进一步处理或记录。


2.3 针对消费者端消息丢失
问题:消费者已经从 Queue 中获取消息,但在处理消息时发生了异常,没有返回 ACK,导致消息丢失。

解决方案:
使用手动确认模式代替自动确认,确保消费者在成功处理完消息后才返回确认。

  1. 手动确认模式:
    • 在消费者处理完消息后,手动调用 channel.basicAck() 来确认消息处理成功。
    • 如果消息处理失败,可以调用 channel.basicNack()channel.basicReject() 来拒绝该消息,RabbitMQ 会重新将消息投递给其他消费者
    • 持久化消费者状态:为了防止在处理消息过程中出现宕机等意外情况,消费者可以将消息处理过程中的中间状态持久化到数据库,确保即使消费者宕机也可以继续未完成的工作。

    • 2.4 RabbitMQ 服务宕机时的消息丢失
      问题:RabbitMQ 宕机导致未持久化的消息丢失。

      解决方案:
      通过持久化消息、队列和集群部署来提高消息的可靠性。

      (1)消息持久化

      生产者可以将消息标记为持久化消息,确保 RabbitMQ 崩溃重启后消息不会丢失:

      MessageProperties.PERSISTENT_TEXT_PLAIN  // 持久化消息
      
      (2)队列持久化

      除了消息,队列本身也需要设置为持久化队列。即使 RabbitMQ 重启,队列依然存在并保存消息:

      channel.queueDeclare("queueName", true, false, false, null);
      
      (3)镜像队列

      为了防止单点故障,可以采用镜像队列,即在 RabbitMQ 的多个节点上复制队列。当主节点宕机时,副本节点可以继续处理消息,保证消息的可靠性。


      三、总结

      要保证 RabbitMQ 的消息不丢失,需要从生产者、路由过程、消费者和 Broker 端采取一系列措施。消息丢失的常见原因包括:生产者发送失败、消息路由失败、消费者处理异常,以及 RabbitMQ 服务宕机未持久化。

      为解决生产者端的消息丢失问题,可以采用事务机制或发布确认机制,确保消息成功发送并得到确认。路由过程中,可以通过 mandatory 参数或设置备份交换机来处理路由失败的情况,确保消息到达队列。消费者端则应使用手动确认模式,保证消息处理完成后才返回 ACK,避免因处理失败导致消息丢失。同时,在 RabbitMQ 宕机的情况下,通过持久化消息和队列、配置镜像队列等方式保证消息不会丢失。

      综合以上机制,RabbitMQ 提供了一个较为全面的消息可靠性保证方案,虽然不能确保 100% 消息不丢失,但可以最大程度上减少消息丢失的风险。


http://www.ppmy.cn/news/1540552.html

相关文章

交叉熵损失函数为代表的两层神经网络的反向传播量化求导计算公式

反向传播(back propagation,BP)算法也称误差逆传播,是神经网络训练的核心算法。我们通常说的 BP 神经网络是指应用反向传播算法进行训练的神经网络模型。反向传播算法的工作机制究竟是怎样的呢?我们以一个两层&#xf…

延迟队列实现及其原理详解

1.绪论 本文主要讲解常见的几种延迟队列的实现方式,以及其原理。 2.延迟队列的使用场景 延迟队列主要用于解决每个被调度的任务开始执行的时间不一致的场景,主要包含如下场景: 1.比如订单超过15分钟后,关闭未关闭的订单。 2.比如用户可以…

Gin框架操作指南10:服务器与高级功能

官方文档地址(中文):https://gin-gonic.com/zh-cn/docs/ 注:本教程采用工作区机制,所以一个项目下载了Gin框架,其余项目就无需重复下载,想了解的读者可阅读第一节:Gin操作指南&#…

Datawhale 组队学习 文生图 Prompt攻防 task03随笔

这期我们从不同角度切入探讨赛题的进阶思路 思路1:对比不同大模型 首先我们可以选择尝试不同的大模型,使用更复杂的大模型可以提高文本改写的质量和效果。随着模型大小的增加,其表示能力也随之增强,能够捕捉更细微的语言特征和语…

STM32—旋转编码器控制直流电机(标准库)

本文使用 KY-040旋转编码器 通过TC1508A电机驱动模块来控制直流电机正转和反转(Speed:0-100),代码部分基于标准库,使用定时器输出比较两个通道来控制PWM输出。 一、KY-040旋转编码器 下图为KY-040旋转编码器&#xf…

MySQL中查询语句的执行流程

文章目录 前言流程图概述最后 前言 你好,我是醉墨居士,今天我们一起探讨一下执行一条查询的SQL语句在MySQL内部都发生了什么,让你对MySQL内部的架构具备一个宏观上的了解 流程图 概述 对于查询语句的SQL的执行流程,主要可以分为…

Golang使用viper读取配置到结构体,但是获取的数据为空

1.viper库 viper库是一个读取配置文件的库,支持多种配置文件,如JSON/TOML/YAML/HCL/envfile/Java properties 等 2.遇到的问题 在使用viper库的时候发现按照相应的配置已经读取到了对应的配置,但是转换为结构体的时候发现怎么拿结构体里面…

什么是非打印字符

1.什么是非打印字符 非打印字符(Non-printable characters)指的是那些无法在终端、控制台或文本编辑器中直接显示为可见符号的字符。它们通常用于控制设备行为或传递特殊信息,而不是作为可见的文本字符。非打印字符包括像空格(\n…