RabbitMQ重试机制

RabbitMQ 重试机制:Auto 与 Manual 消费模式

在 RabbitMQ 消费端,消息消费失败后的重试策略 直接影响系统的可靠性。Spring AMQP 提供了两种消费模式:Auto 模式(自动确认) 和 Manual 模式(手动确认)。

本文详细对比两种模式的差异,重点分析 deliveryTag 的变化规律。


一、核心区别:Tag 的变化

模式 重试时 Tag 变化 原因
Auto 模式 Tag 保持不变 内部重试,同一条消息
Manual 模式(入队) Tag 持续增加 重新入队 = 新消息,产生新 Tag

关键理解:

  • Auto 模式重试是同一条消息在内部重试,Tag 不变
  • Manual 模式 basicNack(requeue=true) 是消息重新入队,相当于新消息,Tag 递增

二、Auto 模式(自动确认)

2.1 配置

yaml 复制代码
spring:
  rabbitmq:
    listener:
      simple:
        acknowledge-mode: auto
        retry:
          enabled: true
          max-attempts: 3          # 最大重试次数
          initial-interval: 1000   # 首次重试间隔(毫秒)
          multiplier: 2            # 间隔倍数

2.2 Tag 变化示例

复制代码
消息到达(Tag=1)→ 消费失败 → 重试(Tag=1)→ 消费失败 → 重试(Tag=1)→ 消费成功
       ↑                      ↑                    ↑
       Tag=1                  Tag=1                Tag=1
       同一条消息             同一条消息           同一条消息

2.3 代码示例

java 复制代码
@RabbitListener(queues = "test-queue")
public void onMessage(String message) {
    System.out.println("收到消息: " + message);
    // 消费失败,自动重试
    // Tag 保持不变,始终是同一条消息
    throw new RuntimeException("消费失败");
}

2.4 Auto 模式特点

特点 说明
Tag 不变 重试时 Tag 保持不变,始终是同一条消息
内部重试 Spring 内部处理,不经过队列
自动入队 重试次数耗尽后,消息重新入队
简单易用 代码简洁,无需手动管理

三、Manual 模式(手动确认)

3.1 配置

yaml 复制代码
spring:
  rabbitmq:
    listener:
      simple:
        acknowledge-mode: manual
        prefetch: 1

3.2 Tag 变化示例(入队)

复制代码
消息到达(Tag=1)→ 消费失败 → basicNack(requeue=true) → 重新入队
                                                              ↓
消息到达(Tag=2)← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← 
       ↑
       Tag=2(新消息)

3.3 代码示例

java 复制代码
@RabbitListener(queues = "test-queue")
public void onMessage(Message message, Channel channel) throws IOException {
    long deliveryTag = message.getMessageProperties().getDeliveryTag();
    System.out.println("当前 Tag: " + deliveryTag);
    
    try {
        // 业务处理...
        channel.basicAck(deliveryTag, false);
    } catch (Exception e) {
        // 重新入队:Tag 会增加(变成新消息)
        channel.basicNack(deliveryTag, false, true);  // requeue=true
    }
}

3.4 Manual 模式三种响应方式

方法 requeue 参数 Tag 变化 说明
basicAck - 消息删除 确认消费
basicNack(requeue=true) true Tag +1 重新入队,变成新消息
basicNack(requeue=false) false 消息删除 丢弃或进入死信队列

四、Tag 变化对比

4.1 完整对比表

场景 Auto 模式 Manual 模式(入队)
首次消费 Tag=1 Tag=1
第1次重试 Tag=1(不变) Tag=2(+1)
第2次重试 Tag=1(不变) Tag=3(+1)
第3次重试 Tag=1(不变) Tag=4(+1)
消息本质 同一条消息 每次都是新消息

4.2 流程对比图

Auto 模式(Tag 不变):

复制代码
                    ┌─────────────────────────────────┐
                    │           内部重试               │
                    │    Tag=1 → Tag=1 → Tag=1        │
                    │         (同一条消息)            │
消息(Tag=1)→ 消费 → 失败 → 重试 → 失败 → 重试 → 成功/入队

Manual 模式(Tag 递增):

复制代码
消息(Tag=1)→ 消费 → 失败 → basicNack(requeue=true)
                                    ↓
                            重新入队(新消息)
                                    ↓
消息(Tag=2)→ 消费 → 失败 → basicNack(requeue=true)
                                    ↓
                            重新入队(新消息)
                                    ↓
消息(Tag=3)→ 消费 → 成功 → basicAck

五、为什么 Tag 会变化?

5.1 Auto 模式原理

复制代码
消费者 ← → Spring 内部队列(内存)
          ↓
     失败后内部重试
          ↓
     Tag 不变(同一条消息)

Auto 模式的重试发生在 Spring 内部,消息从未离开过消费者,所以 Tag 保持不变。

5.2 Manual 模式原理

复制代码
消费者 ← → RabbitMQ Broker
          ↓
     basicNack(requeue=true)
          ↓
     消息回到 Broker 队列
          ↓
     重新投递(新消息,新 Tag)

Manual 模式 basicNack(requeue=true) 是将消息重新放回 Broker,RabbitMQ 会将其视为新消息,分配新的 deliveryTag。


六、注意事项

  1. Manual 入队会导致 Tag 递增 :每次 basicNack(requeue=true) 都会产生新 Tag,可能影响依赖 Tag 的业务逻辑。

  2. Auto 重试是内部机制:Spring 内部重试不经过 Broker,Tag 不变,但重试次数有限。

  3. 幂等性:无论哪种模式,都要保证消费逻辑的幂等性。

  4. 死信队列:Manual 不入队时,建议配置死信队列,避免消息丢失。

  5. 性能:Auto 模式性能高于 Manual 模式。

相关推荐
Flynt12 小时前
Redis Cluster主节点挂了,为什么"高可用"还全员掉线?我把三次kill的记录翻出来了
数据库·redis·分布式
JosieBook14 小时前
【数据库】MySQL 实战精通系列 · 第10篇:分库分表与分布式事务实战
数据库·分布式·mysql
梦帮科技17 小时前
vLLM / TensorRT-LLM 极限推理:PagedAttention 细粒度物理页表管理与连续批处理(Continuous Batching)实战
数据结构·人工智能·分布式·python·深度学习·算法·vllm
Frank_refuel1 天前
分布式RPC框架实战(二):服务端模块划分与底层设计
分布式·网络协议·rpc
mftang2 天前
EtherCAT协议:从“飞读飞写”机制到分布式时钟同步的实时以太网架构深度解析
分布式·架构·ethercat·分布式时钟·从站控制器
ShineWinsu2 天前
对于Redis:Hash类型的解析
c++·redis·分布式·缓存·面试·hash·哈希表
东方芷兰2 天前
Agent 技术摘要 03 —— 基座模型、推理模型、Flash、联邦学习、分布式机器学习
人工智能·分布式·机器学习
程序猿乐锅2 天前
【黑马点评 | 第十一篇】关注 Feed 流实现
java·数据库·redis·分布式·后端·缓存·maven
j7~2 天前
【C++标准项目】C++基于protobuf的发布订阅式消息队列(篇一):项目概述+环境搭建
分布式·消息队列·rabbitmq·gtest·protobuf·muduo·sqlites
今年下半年3 天前
【Spring Boot】多种存储文件(FastDFS / MinIO / 阿里云 OSS)接入设计说明(附源码)
spring boot·分布式·中间件·简单工厂模式·策略模式