RabbitMQ: 高级特性详解之消息返回机制与消费端确认机制

【RabbitMQ】什么是RabbitMQ?RabbitMQ有什么用?应用场景有那些? RabbitMQ简称MQ是一套实现了高级消息队列协议的开源消息代理软件,简单来说就是一个消息中间件。是一种程序对程序的通信方法。 阅读详情

消息返回机制


1 ) 问题背景

在 RabbitMQ 中,生产者将消息发送至 Exchange,Exchange 根据路由规则将消息分发到队列。若消息无法被路由到任何队列(例如 Direct Exchange 未找到匹配的 routingKey),默认情况下消息会被丢弃。

这可能导致业务异常(如订单丢失)。消息返回机制通过设置 mandatory=true,强制 RabbitMQ 将无法路由的消息返回给生产者,由生产者处理异常。

2 ) 核心原理

  1. 触发条件:
    • 生产者发送消息时设置 mandatory=true。
    • Exchange 路由失败(如队列未绑定、routingKey 不匹配)。
  2. 回调流程:
    1. 发送消息
    2. 路由失败
    3. 回调生产者
    Producer
    RabbitMQ Exchange
    ReturnListener
  3. 关键参数:
    • replyCode:状态码(如 312 表示 NO_ROUTE)。
    • replyText:错误描述(如 "NO_ROUTE")。
    • exchange、routingKey:消息的路由信息。
    • body:消息内容。

3 ) 实现方案

import { Channel, connect, Connection } from 'amqplib';
import { Logger } from '@nestjs/common';
 
export class RabbitMQService {
  private connection: Connection;
  private channel: Channel;
  private readonly logger = new Logger(RabbitMQService.name);
 
  async setup() {
    this.connection = await connect('amqp://localhost');
    this.channel = await this.connection.createChannel();
    // 添加 ReturnListener
    this.channel.addReturnListener(this.handleReturn.bind(this));
  }
 
  private handleReturn(
    replyCode: number,
    replyText: string,
    exchange: string,
    routingKey: string,
    properties: any,
    body: Buffer,
  ) {
    this.logger.error(`消息返回!原因: ${replyText} (${replyCode})`);
    this.logger.debug(`Exchange: ${exchange}, RoutingKey: ${routingKey}`);
    this.logger.debug(`消息体: ${body.toString()}`);
    // 业务处理:告警、重试、记录日志等
  }
 
  async publish(
    exchange: string,
    routingKey: string,
    message: string,
  ) {
    const buffer = Buffer.from(message);
    // 关键:设置 mandatory=true
    this.channel.publish(exchange, routingKey, buffer, { mandatory: true });
  }
}

4 ) 注意事项:

  • Channel 生命周期:回调监听需绑定到持久化的 Channel。若 Channel 在消息返回前关闭(如自动关闭的 try 块),回调将失效。
  • 异步回调:handleReturn 由 RabbitMQ 事件循环触发,与主线程分离。
  • 业务处理:在回调中实现补偿逻辑(如订单状态回滚、告警通知)。

消费端确认机制


1 ) 问题背景

默认的自动 ACK 模式下,RabbitMQ 在消息投递到消费者后立即标记为“已确认”。若消费者处理消息时崩溃,消息将永久丢失。手动 ACK 模式要求消费者显式调用 basicAck,确保消息仅在业务完成后确认。

2 ) 核心机制

  1. ACK 类型:
    • 单条确认:channel.basicAck(deliveryTag, false)。
    • 批量确认:channel.basicAck(deliveryTag, true)(不推荐,易出错)。
  2. 重回队列:
    • 通过 basicNack 将消息重新投递到队列(慎用,可能导致死循环)。
  3. 死信队列:
    • 多次重试失败的消息可转入死信队列(DLX)进行隔离处理。

3 ) 实现方案

import { Channel, Message } from 'amqplib';
import { Logger } from '@nestjs/common';
 
export class ConsumerService {
  private channel: Channel;
  private readonly logger = new Logger(ConsumerService.name);
 
  constructor(channel: Channel) {
    this.channel = channel;
  }
 
  async consume(queue: string) {
    // 关闭自动 ACK(autoAck: false)
    await this.channel.consume(queue, async (msg: Message | null) => {
      if (!msg) return;
 
      try {
        this.logger.log(`收到消息: ${msg.content.toString()}`);
        // 业务处理(如订单处理)
        await this.processOrder(msg.content.toString());
        // 手动单条确认
        this.channel.ack(msg);
      } catch (error) {
        this.logger.error(`处理失败: ${error.message}`);
        // 拒绝消息(不重回队列)
        this.channel.reject(msg, false);
      }
    }, { noAck: false }); // 关键:关闭自动 ACK
  }
 
  private async processOrder(orderData: string) {
    // 模拟业务逻辑
    if (Math.random() > 0.5) throw new Error('订单处理异常');
  }
}

关键点:

  • Channel 一致性:确认消息需使用接收消息的 Channel(非新建 Channel)。
  • 错误处理:
    • basicReject(msg, false):直接丢弃消息。
    • basicReject(msg, true) 或 basicNack:重回队列(谨慎使用)。
  • 幂等性:消息可能重复投递,业务逻辑需支持幂等。

工程示例:基于 NestJS 的 RabbitMQ 集成方案


1 ) 方案 1:基础消息生产与消费

配置模块 (rabbitmq.module.ts):

import { Module } from '@nestjs/common';
import { RabbitMQService } from './rabbitmq.service';
import { ConsumerService } from './consumer.service';
 
@Module({
  providers: [RabbitMQService, ConsumerService],
  exports: [RabbitMQService],
})
export class RabbitMQModule {}

生产者服务 (order.service.ts):

import { Injectable } from '@nestjs/common';
import { RabbitMQService } from './rabbitmq.service';
 
@Injectable()
export class OrderService {
  constructor(private readonly rabbitService: RabbitMQService) {}
 
  async createOrder(orderData: any) {
    await this.rabbitService.publish(
      'order_exchange',
      'order.create',
      JSON.stringify(orderData),
    );
  }
}

消费者服务 (restaurant.service.ts):

import { Injectable, OnModuleInit } from '@nestjs/common';
import { ConsumerService } from './consumer.service';
 
@Injectable()
export class RestaurantService implements OnModuleInit {
  constructor(private readonly consumerService: ConsumerService) {}
 
  onModuleInit() {
    this.consumerService.consume('order_queue');
  }
}

2 ) 方案 2:消息返回 + 死信队列

配置死信交换器:

RabbitMQ 命令行配置 
rabbitmqctl set_policy DLX ".*" '{"dead-letter-exchange":"dlx_exchange"}' --apply-to queues 

NestJS 实现:

// rabbitmq.service.ts 扩展
async setupDLX(queue: string, dlxExchange: string) {
  await this.channel.assertExchange(dlxExchange, 'direct');
  await this.channel.assertQueue(queue, {
    deadLetterExchange: dlxExchange, // 绑定死信交换器
  });
}
 
// 在 handleReturn 中处理死信 
private handleReturn(/*...*/) {
  // 将消息转发至死信队列 
  this.channel.publish('dlx_exchange', 'error.route', body);
}

3 ) 方案 3:消费端确认 + 重试策略

指数退避重试:

// consumer.service.ts 扩展
async consumeWithRetry(queue: string, maxRetries = 3) {
  await this.channel.consume(queue, async (msg: Message | null) => {
    if (!msg) return;
 
    let retryCount = msg.properties.headers['x-retry-count'] || 0;
    try {
      await this.processOrder(msg.content.toString());
      this.channel.ack(msg);
    } catch (error) {
      if (retryCount >= maxRetries) {
        this.channel.reject(msg, false); // 最终丢弃
      } else {
        retryCount++;
        // 重新发布消息(添加重试头)
        this.channel.publish('', queue, msg.content, {
          headers: { 'x-retry-count': retryCount },
        });
        this.channel.ack(msg); // 确认原消息
      }
    }
  }, { noAck: false });
}

关键配置:

  • RabbitMQ 参数:
    # 启用延迟插件(重试间隔)
    rabbitmq-plugins enable rabbitmq_delayed_message_exchange
    
  • NestJS 延迟队列:
    await channel.assertExchange('delayed_exchange', 'x-delayed-message', {
      arguments: { 'x-delayed-type': 'direct' },
    });
    

总结


  1. 消息返回机制:
    • 通过 mandatory=true 确保无法路由的消息返回生产者。
    • 适用场景:订单创建、支付回调等需强保证的业务。
  2. 消费端确认:
    • 手动 ACK 避免消息丢失,结合死信队列/重试策略提升可靠性。
    • 避坑指南:
      • 使用同一 Channel 进行消费和确认。
      • 避免重回队列导致死循环。
  3. 工程最佳实践:
    • 生产者:统一封装 RabbitMQ 客户端,集成消息返回监听。
    • 消费者:关闭自动 ACK,实现幂等逻辑,结合重试机制。

补充知识点:

  • RabbitMQ 命令速查:
    • 查看队列绑定:rabbitmqctl list_bindings
    • 监控消息状态:rabbitmqctl list_queues name messages_ready
  • NestJS 生态:
    • 使用 @golevelup/nestjs-rabbitmq 简化集成。
    • 结合 @nestjs/microservices 实现 RPC 模式。

通过上述方案,可构建高可靠的 RabbitMQ 消息系统,确保消息从生产到消费的全链路可控性。

RabbitMQ 高级功能 RabbitMQ 是一个广泛使用的开源消息代理,它支持多种消息传递协议,可以在分布式系统中用于可靠的消息传递。除了基本的消息队列功能外,RabbitMQ 还提供了一些高级功能,增强了其在高可用性、扩展性和灵活性方面的能力。 阅读详情

相关推荐

RabbitMQ消息确认机制

在使用RabbitMQ发送消息如果出现消息没有发送到,队列没有接收到情况。需要消息确认来排错。

ningxiaobai456的博客 1744

rabbitMQ的详细介绍

rabbitMQ的详细介绍

wang20010104的博客 7万+

15.RabbitMQ 消费端手动ACK消息确认机制

  ack——acknowledge(vt. 承认;答谢;报偿;告知已收到;确认的意思),在RabbitMQ中指代的是消费者收到消息后确认的一种行为,关注点在于消费者能否实际接收到MQ发送的消息。   其提供了三种确认方式:   自动确认acknowledge=“none”:当消费者接收到消息的时候,就会自动给到RabbitMQ一个回执,告诉MQ我已经收到消息了,不在乎消费者接收到消息之后业务处理的成功与否。   手动确认acknowledge=“manual”:当消费者收到消息后,不会立刻告诉Rabbit

自能生羽翼,何必仰云梯 5541

【RabbitMQ】MQ的基本概念、RabbitMQ简介及安装

本文涉及MQ的基本概念、RabbitMQ简介、RabbitMQ的安装等内容

十八岁讨厌编程的博客 2万+

RabbitMQ高级特性 - 消费者消息确认机制

为了保证消息从 队列 到 消费者正确消费,那么就引入了消费者消息确认机制.a)消费者在订阅队列时,可以指定 autoAck 参数,根据这个参数设置,消息确认机制分为以下两种(以下讲到的方法和参数来自于 RabbitMQ 原生的 SDK,非 Spring 提供).自动确认:当 autoAck = true 时,RabbitMQ 会自动把发送出去的消息置为确认,然后不管消费者是否真正的消费这些消息,都会从内存中删除.(适合对消息可靠性要求不高的场景).

CYK_byte的博客 1888

KLayout教程(二)编辑不同的形状

首先画一个基础的矩形,然后双击他可以定义他的坐标

集成光电子 1万+

RabbitMQ介绍以及基本使用

消息队列是一种用于在分布式系统中进行通信的技术。它是一种存储和转发消息的中间件,可以用于将应用程序之间的通信解耦,从而实现高效的异步通信。消息队列允许发送者将消息发送到队列中,而接收者则可以从队列中获取消息并进行处理。这种方式可以帮助系统实现高可用性、高性能、松耦合和可伸缩性。消息队列通常包括生产者(发送消息的应用程序)、消费者(接收消息的应用程序)和队列(存储消息的缓冲区)。RabbitMQ:是由erlang语言开发,基于AMQP(高级消息队列协议)协议实现的一种消息队列。市面上还有很多消息队列,比如Ka

qq_40950398的博客 2万+

如何加快香山处理器Chisel->Verilog编译速度

相比使用默认的scala firrtl complier,使用CIRCT能够将香山代码编译到Verilog的速度提高50%左右。在执行make命令时加上MFC=1,例如make verilog MFC=1或make emu MFC=1。在本地从源码编译CIRCT,在编译完成后将circt/bin路径加入PATH中。使用GraalVM免费版作为JVM编译香山比OpenJDK快10%-20%。我们推荐使用GraalVM代替OpenJDK。使用CIRCT编译香山。

专业技术人员的归宿 866

RabbitMQ消息确认机制(ACK)

1、消息确认机制(ACK) 为了保证消息从队列可靠的达到消费者,RabbitMQ 提供了消息确认机制(Message Acknowledgement)。消费者在订阅队列时,可以指定 autoAck 参数,当 autoAck 参数等于 false 时,RabbitMQ 会等待消费者显式地回复确认信号后才从内存(或者磁盘)中移除消息(实际上是先打上删除标记,之后在删除)。当 autoAck 参数等于 true 时,RabbitMQ 会自动把发送出去的消息置为确认,然后从内存(或者磁盘)中删除,而不管消费者是否

pan_junbiao的博客 4万+

DeepSeek Harness 实战:构建可编排的 Agent 插件与工作流

在大模型应用开发中,AI Agent 的落地常面临逻辑耦合、工具接入繁琐、流程难以编排等工程化痛点。DeepSeek Harness 作为一种面向 Agent 运行时的开发层,将模型调用、插件扩展、工作流编排与执行状态统一收敛,为开发者提供可维护、可观测的控制框架。它并非替代 LangChain 或 Dify,而是更聚焦于模型为核心的应用组装范式:插件承载可复用的能力单元,工作流定义节点间的条件跳转与数据传递,从而让复杂业务既能可视化设计,又能通过代码深度定制。从客服知识库到 PRD 评审助手,这类模式适用

weixin_33805743的博客 336

MOS管热阻的测量方法

实验室内如何测试mos管热阻

weixin_43492562的博客 4095

详解RabbitMQ高级特性之消息确认机制

详解RabbitMQ高级特性之消息确认机制。

. 3146

工业自动化进阶:西门子 S7-1200 PLC 调度 AGV 实现精确定点移动

本文介绍了基于西门子S7-1200PLC的AGV调度控制系统设计,包括系统架构、硬件选型和PLC程序设计。系统通过PROFINET通信实现PLC与AGV的数据交互,采用状态机控制逻辑实现任务管理、运动控制和闭环位置校正。重点阐述了通信协议实现、梯形图核心逻辑及系统调试优化方法。实际应用案例显示,该系统定位精度达±3mm,显著提升了物料配送效率。该方案为工业自动化升级提供了可靠的技术支持。

qq_52407556的博客 1891

RabbitMq的一些概念,持久化、队列排他、自动删除、消息确认机制、消息ACK、消费消息的模式

一、队列持久化的概念 队列的声明默认是存放到内存中的,如果rabbitmq重启会丢失,如果想重启之后还存在就要使队列持久化,保存到Erlang自带的Mnesia数据库中,当rabbitmq重启之后会读取该数据库。 二、排他 简单理解就是在连接关闭时是否会删除队列(无论队列中有没有消息) 三、自动删除 当队列中有消息时,无论是否排他,关闭连接都不会删除队列,此时消费者消费完消息后再断开消费者,队列会被自动删除。(这里如果有多个消费者消费同一个队列,则需要所有消费者都断开后才能自动删除) 四、消..

毅呀毅呀哟 7896

解决Word中英文混排的5个常见排版问题(含单词换行、间距调整等)

本文详细解析Word中英文混排的5大常见排版问题,包括单词换行、间距调整、标点混用等,提供专业解决方案。通过设置段落格式、调整兼容性选项和使用字体组合等技巧,帮助用户轻松解决文档排版难题,提升专业性和阅读体验。

vim8coder的博客 1345

基于Simulink的电动汽车动力总成控制策略验证与标定仿真平台

电动汽车的动力总成(Powertrain)是车辆的核心系统,包括动力电池、电机控制器、逆变器和驱动电机等关键部件。动力总成的控制策略直接影响车辆的动力性能、能耗效率和驾驶体验。为了验证和优化这些控制策略,基于MATLAB/Simulink的仿真平台成为一种高效且经济的解决方案。本项目旨在构建一个完整的基于Simulink的电动汽车动力总成控制策略验证与标定仿真平台,涵盖控制策略建模、性能评估以及参数标定等功能模块,并通过仿真验证系统的有效性。

xiaoheshang_123的博客 177

【MQ篇】RabbitMQ的消费者确认机制实战!

RabbitMQ 把消息发给消费者,如果消费者还没来得及处理完就“嗝屁了” 😵‍💫(程序崩溃、网络断开、处理异常),那这条消息对于 RabbitMQ 来说可能已经“送达”了,然后就被无情地从队列里删除了!如果在收到确认信号之前,消费者断开连接了,或者明确表示处理失败了,RabbitMQ 就会知道这条消息“有问题”,会考虑把这条消息重新发给其他消费者,或者等这个消费者恢复后再发给它。但如果家里没人,包裹被风吹走了 💨,或者被隔壁老王的狗叼走了 🐶📦💥,或者你拿到包裹后,手一滑掉粪坑里了 🚽…

qq_56158663的博客 3555

YOLO11的持续学习:如何在不遗忘旧数据的情况下学习新类别

类增量学习(Class-Incremental Learning, CIL)是持续学习(Continual Learning)的一个重要分支,它指的是模型在不遗忘已学旧类别知识的前提下,逐步学习新类别的能力。与传统机器学习假设所有数据一次可用不同,类增量学习更贴近现实世界应用场景——新的类别数据往往会随着时间推移逐步出现。 举个例子,假设我们已经训练好一个YOLOv11模型用于检测"猫"和"狗"两种动物,现在需要让模型新增识别"兔子"的能力。传统方法需要收集所有类别(猫、狗、兔子)的数据重新训练,而类增量

本博客聚焦 YOLOv11 全流程落地,涵盖架构优化、数据集处理、训练技巧与多场景部署,兼及国产数据库、Java 开发与 AI 模型应用,内容兼顾理论与工程实践,为开发者提供系统干货,助力高效提升技术能力。 1967

RabbitMQ消费端之消息确认及消息预取详解

阅读本文之前,请先查看基础安装及操作:RabbitMQ 基本api使用 以及和spring、springboot整合 1. 消费者如何确认消费? 为什么要确认消费? 默认情况下 消费者在拿到rabbitmq的消息时 已经自动确认这条消息已经消费了, 讲白话就是rabbitmq的队列里就会删除这条消息了, 但是 我们实际开发中 难免会遇到这种情况, 比如说 拿到这条消息 发现我处理不了 比如说 参数...

qqxhb 资源共享 2503

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

【RabbitMQ】RabbitMQ 消息的可靠性 —— 生产者和消费者消息的确认,消息的持久化以及消费失败的重试机制

在现代分布式应用程序中,消息队列扮演了至关重要的角色,允许系统中的各个组件之间进行异步通信。这种通信模式提供了高度的灵活性和可伸缩性,但也引入了一系列的挑战,其中最重要的之一是消息的可靠性。首先让我们来了解一下,在消息队列中,消息从生产者发送到交换机,再到队列,最后到消费者,有哪些情况会导致消息的丢失?生产者发送的消息未送达交换机;消息到达交换机后未到达队列;MQ 宕机,队列中的消息会丢失;消费者接收到消息后未消费就宕机了。

qq_61635026的博客 1万+

pscad IEEE标准系统搭建说明

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

rabbitmq消费消息确认及消费失败重试机制

这里主要是针对springboot中的rabbitmqtemplate来说的 基础代码以查看此专栏相关文章 消费者消息确认 RabbitMQ是阅后即焚机制,RabbitMQ确认消息被消费者消费后会立刻删除。 而RabbitMQ是通过消费者回执来确认消费者是否成功处理消息的:消费者获取消息后,应该向RabbitMQ发送ACK回执,表明自己已经处理消息。 设想这样的场景: 1)RabbitMQ投递消息给消费者 2)消费者获取消息后,返回ACK给RabbitMQ 3)RabbitMQ删除消息 4)消费者宕机,消

优雅永不过时 1万+

RabbitMq 消息确认机制详解

消息从发送,到消费者接收,会经理多个过程,其中的每一步都可能导致消息丢失,常见的丢失原因包括: 生产者发送的消未送达exchange 消息到达exchange后未到达queue 针对这些问题,RabbitMQ分别给出了解决方案: 生产者确认机制 mq持久化消费者确认机制 失败重试机制 ​

weixin_52278591的博客 5642

【RabbitMQ】-----详解RabbitMQ高级特性之消息确认机制

此时我们可以看到,消费消息时发生异常,导致消息没有被正常消费,而且此时控制台不断地打印日志,deleverTag的值不断增加,观察控制界面可以看到队列中始终有一条消息,是因为AUTO机制下,如果消费消息时发生异常,此时消费方不会确认消息,此时消息就会重新入队,直到消费方能够正常消费消息而不发生异常。这种模式下, 消息⼀旦投递给消费者, 不管消费者是否成功处理了消息, RabbitMQ 就会⾃动确认消息, 从RabbitMQ队列中移除消息. 如果消费者处理消息失败, 消息可能会丢失.

mr_yuanshen的博客 1527

操作008-03:消费端消息确认

操作008-03:消费端消息确认

程序员码小跳 5104

【RabbitMQ】高级特性—消息确认详解

消息确认机制是RabbitMQ确保消息可靠传递的重要功能。文章介绍了两种确认模式:自动确认(autoAck=true)和手动确认(autoAck=false)。自动确认适合对可靠性要求不高的场景,消息投递后立即删除;手动确认则需要消费者显式调用Basic.Ack命令,适合高可靠性场景。RabbitMQ会将未确认消息标记为Unacked状态,若消费者断开连接则重新入队。文章详细讲解了三种确认方法:basicAck(肯定确认)、basicReject(单条否定确认)和basicNack(批量否定确认),并提供了

Yeeear的博客 1470

RabbitMQ自学之路(七)—— RabbitMQ消息发送确认与消息接收确认机制

通常,一个消息被消费者消费后,就会从Queue中移除了。这是因为RabbitMQ默认会在消息被消费者接收后,立即确认。 但存在丢失消息的可能,如果消费端消费逻辑抛出异常,也就是消费端没有处理成功这条消息,那么就相当于丢失了消息。 另外一种情况就是,我们在spring中处理消息时,即使消息处理没出异常,但是后续代码出异常造成回滚,这样其实也相当于丢失消息。 所以一般情况下,手动确认要比较好一些。 达...

互联网叫兽 9257
上一篇: RabbitMQ: 消息可靠性保障机制深度解析与工程实践
下一篇: RabbitMQ: 消息过期机制与死信队列技术解析
Wang's Blog
博客等级 码龄12年 7438粉丝 2422原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wang's Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值