当前位置: 首页 > news >正文

【rabbitmq 高级特性】全面详解RabbitMQ重试机制

目录

全面详解RabbitMQ重试机制

一、核心概念:为什么需要重试?

二、Spring-AMQP的重试配置

三、代码实战:配置与使用

四、重试机制的模式与陷阱

五、总结


一、核心概念:为什么需要重试?

在消息消费过程中,可能会遇到各种临时性故障,例如:

  • 网络波动​:导致数据库连接短暂中断。

  • 外部服务不可用​:依赖的第三方API暂时超时或无响应。

  • 资源竞争​:如数据库死锁。

这些故障通常是短暂的,稍后重试就可能会成功。重试机制就是为了自动处理这类情况,避免因临时问题导致消息消费失败,从而提高系统的健壮性。

重要前提​:重试机制只对AcknowledgeMode.AUTOAcknowledgeMode.NONE模式有效,并且通常用于处理消费者逻辑中的异常。对于AcknowledgeMode.MANUAL模式,重试的控制权完全在消费者自己手中。

二、Spring-AMQP的重试配置

Spring AMQP提供了一套声明式的重试配置,非常易于使用。核心配置都在 application.yml中完成。

spring:rabbitmq:listener:simple:retry:enabled: true           # 开启重试机制max-attempts: 5        # 最大重试次数(包括第一次调用)initial-interval: 1000ms # 第一次重试的间隔时间multiplier: 2.0        # 间隔时间乘子(下次间隔 = 上次间隔 * multiplier)max-interval: 10000ms  # 最大重试间隔时间

参数详解​:

  • max-attempts: 5:最多尝试5次(1次原始调用 + 4次重试)。

  • initial-interval: 1s:第一次失败后,等待1秒进行第一次重试。

  • multiplier: 2.0:间隔时间按倍数增长。

  • max-interval: 10s:无论乘子计算出的值多大,间隔时间不会超过10秒。

根据以上配置,重试间隔时间将按以下序列进行:​1s → 2s → 4s → 8s → 10s (max)​

下图清晰地展示了在自动确认模式下,消息从投递到最终被确认或拒绝的完整重试生命周期:

三、代码实战:配置与使用

1. 配置重试机制 (application.yml)​

spring:rabbitmq:addresses: amqp://study:study@110.41.51.65:15673/bitelistener:simple:acknowledge-mode: auto # 重试通常在AUTO模式下工作retry:enabled: truemax-attempts: 3       # 重试2次(共调用3次)initial-interval: 2000ms # 初始间隔2秒multiplier: 1.5      # 下次间隔是上一次的1.5倍max-interval: 5000ms  # 最大间隔5秒

2. 声明队列和交换机

public class Constant {public static final String RETRY_EXCHANGE_NAME = "retry_exchange";public static final String RETRY_QUEUE = "retry_queue";
}@Configuration
public class RetryConfig {@Bean("retryExchange")public Exchange retryExchange() {return ExchangeBuilder.fanoutExchange(Constant.RETRY_EXCHANGE_NAME).durable(true).build();}@Bean("retryQueue")public Queue retryQueue() {return QueueBuilder.durable(Constant.RETRY_QUEUE).build();}@Bean("retryBinding")public Binding retryBinding(@Qualifier("retryExchange") Exchange exchange,@Qualifier("retryQueue") Queue queue) {return BindingBuilder.bind(queue).to(exchange).with("").noargs();}
}

3. 生产者发送消息

@RestController
@RequestMapping("/producer")
public class ProducerController {@Autowiredprivate RabbitTemplate rabbitTemplate;@RequestMapping("/retry")public String retry() {rabbitTemplate.convertAndSend(Constant.RETRY_EXCHANGE_NAME, "", "retry test...");return "发送成功!";}
}

4. 消费者模拟失败与重试

@Component
public class RetryQueueListener {@RabbitListener(queues = Constant.RETRY_QUEUE)public void listenerQueue(Message message) throws Exception {System.out.printf("尝试消费消息: %s, 时间: %s%n",new String(message.getBody(), "UTF-8"),new SimpleDateFormat("HH:mm:ss").format(new Date()));// 模拟处理失败,抛出异常int num = 3 / 0; // 此处会抛出ArithmeticException: / by zeroSystem.out.println("处理完成");}
}

5. 运行结果与分析

调用接口发送消息后,控制台会输出类似以下日志,清晰地展示了重试过程:

尝试消费消息: retry test..., 时间: 14:20:01
尝试消费消息: retry test..., 时间: 14:20:03  (等待了 ~2s)
尝试消费消息: retry test..., 时间: 14:20:06  (等待了 ~3s)
2024-04-29T17:17:21.819+08:00 WARN 32172 --- [ntContainer#0-1] o.s.a.r.r.RejectAndDontRequeueRecoverer : Retries exhausted for message (Body:'retry test...' MessageProperties[headers={}, ...])
org.springframework.amqp.rabbit.support.ListenerExecutionFailedException: Listener method 'public void com...RetryQueueListener.listenerQueue(org.springframework.amqp.core.Message) throws java.lang.Exception' threw exceptionat org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:152)... 60 common frames omitted
Caused by: java.lang.ArithmeticException: / by zeroat com.bite.rabbitmq.listener.RetryQueueListener.listenerQueue(RetryQueueListener.java:20)... 72 common frames omitted

结果解读​:

  1. 消费者共收到了3次消息(1次初始调用 + 2次重试)。

  2. 重试间隔基本符合配置:2秒3秒2 * 1.5 = 3)。

  3. 重试次数耗尽(max-attempts=3)​后,Spring会抛出ListenerExecutionFailedException,并打印异常栈。

  4. 最关键的一点​:在AUTO模式下,重试耗尽后,消息会被自动确认(Ack)​并从队列中删除。如流程图所示,这会导致消息丢失​!因为框架认为你已经无法处理这条消息了。

四、重试机制的模式与陷阱

1. 自动确认模式(AUTO)下的重试

  • 工作方式​:由Spring AMQP框架自动控制。消费失败后,框架会捕获异常,等待配置的间隔时间,然后重新投递消息。

  • 优点​:配置简单,无需编写重试逻辑。

  • 致命陷阱​:如图表所示,重试耗尽后消息会被自动确认,导致消息丢失。适用于允许极少数消息丢失的非核心业务。

2. 手动确认模式(MANUAL)下的重试

  • 工作方式​:重试的控制权完全交给开发者。你需要自己捕获异常,并决定是直接确认(成功)、拒绝并重试(basicNack+ requeue=true)还是拒绝并丢弃(basicNack+ requeue=false)。

  • 代码示例​:

    @Component
    public class ManualRetryListener {@RabbitListener(queues = Constant.RETRY_QUEUE, ackMode = "MANUAL")public void listenerQueue(Message message, Channel channel) throws Exception {long deliveryTag = message.getMessageProperties().getDeliveryTag();try {// 业务逻辑System.out.println("处理消息...");int num = 3 / 0; // 模拟失败channel.basicAck(deliveryTag, false); // 成功则确认} catch (Exception e) {System.out.println("处理失败,准备重试...");// 拒绝消息,并让消息重新入队(requeue=true)以实现重试// 注意:这样会立即重试,没有间隔,可能造成无限循环和积压channel.basicNack(deliveryTag, false, true);// 更佳实践:记录重试次数,达到一定次数后不再requeue,而是记录日志或转入死信队列// if (retryCount < MAX_RETRY) {//     channel.basicNack(deliveryTag, false, true);// } else {//     channel.basicNack(deliveryTag, false, false); // 丢弃或进入死信// }}}
    }
  • 优点​:控制灵活,可靠性高。

  • 缺点​:需要编写更多代码,并自行实现重试间隔、最大次数等逻辑,否则直接requeue=true容易引起无限重试循环

五、总结

模式

配置

控制权

重试耗尽结果

适用场景

自动重试 (AUTO)​

simple.retry

Spring框架

消息丢失

允许少量丢失的非核心业务

手动控制 (MANUAL)​

acknowledge-mode: manual

开发者

消息积压(需自行处理)

要求高可靠性的核心业务

  1. 谨慎使用自动重试​:明确其会导致消息丢失的后果,仅用于非关键业务。

  2. 死信队列是最终保障​:无论是自动还是手动模式,都应配置死信队列(DLX)。在手动模式下,当重试多次失败后,应使用 channel.basicNack(deliveryTag, false, false)拒绝消息并不重新入队,同时确保队列配置了死信交换机,这样消息就会自动转入死信队列,供后续人工排查处理。

  3. 重试策略选择​:对于临时性故障(网络抖动),使用指数退避重试(如配置的multiplier)非常有效。对于永久性故障(代码BUG、消息格式错误),应立即失败,避免无意义的重试。

  4. 幂等性​:由于消息可能会被多次投递(重试机制的本质),​消费者逻辑必须实现幂等性,即同一消息处理多次的结果与处理一次是相同的。这是使用重试机制的前提。

http://www.dtcms.com/a/414961.html

相关文章:

  • 在飞腾D2000/8平台下ubuntu内核添加WX1860和WX1820的驱动
  • docker相关进程的作用
  • 建设的网站如何让用户注册宁波发布最新通报
  • [LVGL] 中国象棋
  • 通过XShell使用Git三板斧
  • 【Git】远程操作 + 给命令配置别名 + 标签管理
  • 教学网站建设计划免费ppt下载网站
  • 给客户做网站需要提供看电视剧免费的网站
  • 分治法找到数组中出现次数超过一半的元素
  • C语言入门知识点(12.回调函数与qsort函数的模拟与实现)
  • 徐州网站客户如何做网站的seo优化
  • 岳阳网站建设哪家好海北高端网站建设公司
  • MyBatis中如何实现数据封装
  • Http 常见的状态码
  • [论文阅读] 人工智能 | 突破AI大模型算力瓶颈:下一代计算范式的三大演进路径探索
  • 杭州高端设计网站建设dede旅游网站
  • 网站建设绪论江苏天宇建设集团官方网站
  • 开发知识点-Python-virtualenv
  • 网站如何做线下的市场推广网站开发工程师证
  • 珠海市网站建设的公司软件开发与设计
  • 好紧张,第一次接吻是一种什么感觉
  • 学做网站看什么书网站定制分享
  • 基于机器学习的心血管疾病智能预测系统
  • 上海专业的网站公多语网站wordpress子站点
  • vscode和cursor中引入prettierrc进行格式化
  • 常见算法实现系列01 - 排序算法
  • 做兼职去什么网站wordpress 预加载动画
  • XCOSnTh单片机的串口
  • SSR/SSG:Next.js、Nuxt.js的SEO优化与缓存策略
  • 我想做个网站推广怎么做苏州好的网络科技公司