RabbitMQ 高级特性——重试机制

news2024/9/27 7:51:48

在这里插入图片描述

文章目录

  • 前言
  • 重试机制
    • 配置文件设置
    • 生命交换机、队列和绑定关系
    • 生产者发送消息
    • 消费消息

前言

前面我们学习了 RabbitMQ 保证消息传递可靠性的机制——消息确认、持久化和发送发确认,那么对于消息确认和发送方确认,如果接收方没有收到消息,那么这时该怎么做呢?这就要提到 RabbitMQ 的重试机制了,当发送方发送的消息没有成功到达接收方,那么发送方就会使用重试机制来向接收方重新发送消息,如果接收方因为程序逻辑错误引起的,那么不管发送方重新发送多少次,接收方都不能正确的处理这个消息,那么发送方也不能无休止的向接收方发送消息,当发送的次数超过某个数量的时候,那么这个消息就会被标记为死信,然后被处理掉。那么这篇文章将详细的说明一下 RabbitMQ 的重试机制。

重试机制

RabbitMQ的重试机制是一种强大的功能,它允许在消息处理失败时自动重试,从而提高系统的可靠性和稳定性。

重试机制的触发条件

  1. 消息发送失败:当消息发送到RabbitMQ服务器时,如果因为网络问题、认证失败或其他原因导致发送失败,RabbitMQ会尝试重试发送。
  2. 消息消费失败:当消费者从队列中获取消息并尝试处理时,如果因为某种原因(如业务逻辑错误、系统异常等)导致处理失败,RabbitMQ会根据预设的重试策略进行重试。

我们都知道 Spring AMQP 提供了四种确认策略:NONE、MANUAL、AUTO。当确认策略为 NONE 的时候队列不管这个消息是否被成功处理都会将这个消息从队列中删除,而确认策略为 MANUAL 的时候则更多的靠程序本身处理,那么重试机制更多的使用在确认策略为 AUTO 的情况下。

配置文件设置

spring:
  rabbitmq:
    addresses: amqp://admin:admin@x.x.x.x:5672/test
    listener:
      simple:
        acknowledge-mode: auto # 确认模式
        retry:
          enabled: true # 开始重试机制
          initial-interval: 5000ms # 每次重试的间隔时间
          max-attempts: 5 # 最大重试次数

生命交换机、队列和绑定关系

public class Constants {
    public static final String RETRY_EXCHANGE = "retry.exchange";
    public static final String RETRY_QUEUE = "retry.queue";
}
@Configuration
public class RabbitConfig {
    @Bean("retryExchange")
    public DirectExchange retryExchange() {
        return ExchangeBuilder.directExchange(Constants.RETRY_EXCHANGE).durable(true).build();
    }

    @Bean("retryQueue")
    public Queue retryQueue() {
        return QueueBuilder.durable(Constants.RETRY_QUEUE).build();
    }

    @Bean("retryBinding")
    public Binding retryBinding(@Qualifier("retryQueue") Queue queue, @Qualifier("retryExchange") DirectExchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with("retry");
    }
}

生产者发送消息

@RequestMapping("/producer")
@RestController
public class ProducerController {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    
    @RequestMapping("/retry")
    public String retry() {
        rabbitTemplate.convertAndSend(Constants.RETRY_EXCHANGE,"retry","rabbitmq retry");
        return "消息发送成功";
    }
}

消费消息

@Component
public class RetryListener {
    @RabbitListener(queues = Constants.RETRY_QUEUE)
    public void listener(Message message, Channel channel) {
        System.out.println("接收到消息:" + message + channel);
        //制造出异常使得消费者不能正常处理消息
        int ret = 3/0;
        System.out.println("消息处理成功");
    }
}

我们先将重试机制的配置给注释掉,然后运行之后会发现消费者会重复读取一条消息并且一直抛异常,这是因为:

由于监听器方法抛出了异常并且没有被捕获,Spring AMQP将不会发送ACK,RabbitMQ将不断重新投递这条消息给消费者,直到它最终被确认、被拒绝(并可能发送到死信队列)或队列被删除。

那么我们配置重试机制的重试次数之后再看看什么效果:

在这里插入图片描述

可以发现,当配置了重试次数之后,包括第一次投递消息,队列一共给消费者发送了五次消息,并且这个五次的消息的 deliveryTag 是一样的,也就说明是队列的重试机制投递的,五次之后队列便不再向该消费者发送该消息,这样就避免了因消费者的程序逻辑问题而导致队列无休止的向消费者发送消息的问题,并且还保证了消息传递的可靠性。

那么我们将消息的确认策略更换为 MANUAL 手动确认的方式,然后看看这个重试机制的配置会不会生效:

@RabbitListener(queues = Constants.RETRY_QUEUE)
public void listener(Message message, Channel channel) throws IOException, InterruptedException {
    long deliveryTag = message.getMessageProperties().getDeliveryTag();
    try {
        System.out.println("接收到消息:" + message + channel);
        //制造出异常使得消费者不能正常处理消息
        int ret = 3/0;
        System.out.println("消息处理成功");
        channel.basicAck(deliveryTag,false);
    } catch (Exception e) {
        Thread.sleep(1000);
        //第三个参数requeue表示被拒绝的消息是否重新进入队列,true表示重新进入队列并且重新投递这个消息,否则直接丢弃
        channel.basicNack(deliveryTag,false,true);
    }
}

在这里插入图片描述
发现当确认策略为 manual 手动确认的时候,我们的重试机制的配置是不生效的,并且可以发现我们的消息的 deliveryTag 是不断递增的,也就是说之前拒绝的消息每次都会重新入队列然后重新投递,跟重试机制是不一样的。

而如果我们 basicNack 方法的第三个参数 requeue 参数的值为 fasle 时候,那么这个被拒绝的消息就会被丢弃或者投递到的死信队列中。

使用重试机制时需要注意:

  1. 自动确认模式下:程序逻辑出现异常,即使多次重试还是失败,消息也会被自动确认,那么这条消息就会丢失。

  2. 在手动确认模式下,消费者需要显式地发送ACK(Acknowledgment)或NACK来告诉RabbitMQ消息是否已被成功处理。如果发生异常且没有发送ACK,消息将保持为unacked状态,这允许RabbitMQ重新将消息发送给其他消费者(如果配置了多个消费者)或根据队列的其他配置(如死信队列)来处理未确认的消息。然而,如果所有消费者都无法处理该消息,它将导致消息在队列中积压,除非配置了适当的超时机制或死信队列来处理这些长时间未确认的消息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2169382.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

每日一题:⻓度最⼩的⼦数组

文章目录 一、题目二、解析1、暴力算法(1)纯暴力(2)前缀和 循环 2、滑动窗口 一、题目 209. 长度最小的子数组 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其总和大于等于 target 的长度最小的 子数组…

Java项目实战II基于Java+Spring Boot+MySQL的IT技术交流和分享平台的设计与实现(源码+数据库+文档)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发,CSDN平台Java领域新星创作者,专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 在当今信息…

归并排序,外排序,计数排序(非比较排序)

归并排序:(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序…

Studying-图论包含的算法总结

目录 1.DFS(深度优先搜索) 代码框架: 2. BFS(广度优先搜索) 代码框架: 3. 并查集 4.最小生成树之Prim 5.最小生成树之Kruskal 6.拓扑排序 7. 最短路径之-dijkstra(朴素版&#xff…

R语言非参数回归预测摩托车事故、收入数据:局部回归、核回归、LOESS可视化...

全文链接:https://tecdat.cn/?p37784 非参数回归为经典(参数)回归方法提供了一种灵活的替代方法。与假定回归关系具有依赖于有限数量的未知参数的已知形式的传统(参数)方法不同,非参数回归模型尝试从数据样…

UE虚幻引擎云渲染汽车动画的优势!

在汽车广告和动画制作领域,虚幻引擎(UE)结合云渲染技术正掀起一场技术革命。这项技术以其高性能、成本效益和灵活性,为创作者提供了强大的工具,以实现更加逼真和高效的汽车动画制作。 一、为什么选择UE虚幻引擎制作汽车…

针对考研的C语言学习(定制化快速掌握重点3)

1.数组常见错误 数组传参实际传递的是数组的起始地址&#xff0c;若在函数中改变数组内容&#xff0c;数组本身也会发生变化 #include<stdio.h> void change_ch(char* str) {str[0] H; } int main() {char ch[] "hello";change_ch(ch);printf("%s\n&q…

【YashanDB知识库】YMP迁移oracle不兼容给用户授权高级包

本文转自YashanDB官网&#xff0c;具体内容请见https://www.yashandb.com/newsinfo/7441382.html?templateId1718516 【标题】YMP迁移oracle不兼容给用户授权高级包 【关键字】oracle迁移&#xff0c;高级包授权 【问题描述】迁移评估任务中&#xff0c;oracle迁移YashanDB…

衡石分析平台系统管理手册-功能配置之全局 CSS 设置

全局 CSS 设置​ 衡石系统提供了全局 CSS 功能。通过自定义全局 CSS 可以更加精细化控制页面视觉效果&#xff0c;例如可以通过 display:none CSS 规则来隐藏不需要展示的功能。 使用场景​ 全局 CSS 可以控制页面外观&#xff0c;常用于以下场景。 场景1&#xff1a;控制页…

Golang | Leetcode Golang题解之第438题找到字符串中所有字母异位词

题目&#xff1a; 题解&#xff1a; func findAnagrams(s, p string) (ans []int) {sLen, pLen : len(s), len(p)if sLen < pLen {return}count : [26]int{}for i, ch : range p {count[s[i]-a]count[ch-a]--}differ : 0for _, c : range count {if c ! 0 {differ}}if diff…

如何展开浏览器开发者模式的Fetch/XHR

说明&#xff1a;大多数程序员都用浏览器的F12&#xff0c;开发者模式查看接口&#xff0c;我也不例外。我常用下面这个选项&#xff0c;它会过滤掉掉其他文档、样式请求&#xff0c;只展示访问服务器的接口请求 有次&#xff0c;不知道点了什么&#xff0c;这个菜单消失找不…

Redis——缓存

什么是缓存&#xff1f; 缓存是计算机中一个经典的概念&#xff0c;其实本质就是将常用的数据放到访问速度快的地方&#xff0c;方便读取。 对于硬件的访问速度来说&#xff0c;通常情况如下&#xff1a; CPU寄存器 > 内存 > 硬盘 > 网路 但是对于计算机硬件来说&am…

李沐深度学习-多层感知机、模型选择、过拟合、欠拟合

3.8.1 隐藏层 多层感知机在单层神经网络的基础上引入了一到多个隐藏层&#xff08;hidden layer&#xff09;。隐藏层位于输入层和输出层之间。图3.3展示了一个多层感知机的神经网络图&#xff0c;它含有一个隐藏层&#xff0c;该层中有5个隐藏单元。 图3.3 带有隐藏层的多层感…

JavaSE篇之String类

1.字符串的构造 常用的有三种方法&#xff1a; 1.使用常量串构造 2.直接newString对象 3.使用字符数组进行构造 2.String对象的比较 2.1比较是否引用同一个对象 对于基本类型变量&#xff0c; 比较两个变量中存储的值是否相同。 对于引用类型变量&#xff0c;比较两个引用…

使用 MongoDB 在 Spring Boot 中构建安全的 RBAC 系统

介绍 您是否曾经构建过应用程序&#xff0c;然后突然意识到需要以更精细的方式管理用户访问权限&#xff1f;也许您已经硬编码了一些管理检查或在整个代码库中分散了权限逻辑。相信我&#xff0c;我经历过这种情况&#xff0c;维护起来并不好玩。 这就是基于角色的访问控制 (…

Unity3D地形系统一口气讲完!谢啦!!☆⌒(*^-゜)v

Unity 3D 地形系统概述 在三维游戏世界中&#xff0c;通常会将丰富多彩的游戏元素融合在一起&#xff0c;比如游戏中起伏的地形、郁郁葱葱的树木、蔚蓝的天空、、凶恶的猛兽等&#xff0c;营造出身临其境的游戏沉浸感&#xff0c;让玩家置身游戏世界&#xff0c;忘记现实。 地…

定时任务上云改造方案

优质博文&#xff1a;IT-BLOG-CN 一、Job单元化 什么Job需要单元化&#xff1a;所有会往单元化DB更新/删除/插入数据的Job都需要进行单元化改造。 什么是单元化DB 【1】指配置为DRC双向复制的DB&#xff1b; 【2】单元化的DB部署在多个Zone&#xff0c;每个Zone内的实例都会…

【含文档】基于Springboot+Vue的高校失物招领平台(含源码+数据库+lw)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 系统定…

物体实例分割,机器人拾取

物体实例分割是计算机视觉领域的一个关键任务&#xff0c;它旨在从图像中分割出每个独立物体&#xff0c;并且为每个物体实例提供一个独特的标识。这一任务不仅识别出图像中的物体&#xff0c;还能区分出多个同类物体的不同实例&#xff0c;例如在一张桌子上摆放的多个相同的杯…

『功能项目』宠物的攻击巨型化【80】

本章项目成果展示 我们打开上一篇79宠物的召唤跟随的项目&#xff0c; 本章要做的事情是实现在战斗中有几率触发宠物巨型化攻击将怪物击飞的效果 首先在主角预制体中增加隐藏的宠物巨型化 制作巨型化宠物的攻击效果 将该动画控制器放置在隐藏的巨型化宠物的动画控制器上 首先查…