【Fifty Project - D35】

今日完成记录

TimePlan完成情况
7:00 - 7:40爬坡
8:30 - 11:30Rabbit MQ
17:30 - 18:30羽毛球

RabbitMQ

消费者端如何保证可靠性?

  • 消息投递过程出现网络故障
  • 消费者接收到消息但是突然宕机未消费消息
  • 消费者接收到消息后处理不当抛出异常
  • 。。。

消费者确认机制

Consumer Acknowledgement:消费者处理消息结束应该给MQ发送一个回执,告知自己的消息处理状态:ack【成功处理消息,MQ从队列中删除消息】nack【消息处理失败,MQ需要重新推送消息】reject【消息处理失败并拒绝该消息,MQ从队列删除消息】

springAMQP提供了三种ACK处理方式:

  • none:不处理,消息投递给消费者后直接返回ack【不安全,不建议】
  • manual:手动处理,自己在业务代码中调用api发送ack或者reject【存在业务入侵但是更灵活】
  • auto:自动处理,利用aop自动对业务代码进行增强,正常执行则返回ack,出现异常则根据异常类型处理【业务异常返回nack, 消息处理或者校验异常返回reject】

返回reject常见异常:MessageConversionException、MethodArgumentNotValidException、MethodArgumentTypeMissmatchException、NoSuchMethodException、ClassCastException
基本上就是消息校验异常以及不匹配处理方法或者参数的异常

通过如下配置可以设置ack处理方法:

spring:rabbitmq:listener:simple:acknowledge-mode: none # 不做处理

1、测试none处理方式,修改消费者端代码,使其抛出触发reject的异常。在抛出异常前打断点,并观察发现rabbitmq的客户端发现消息在发送到消费者则触发了自动ack并且删除了消息 ,触发异常后客户端并没有做任何处理。
在这里插入图片描述

2、修改acknowledge-mode为auto,再观察发现阻塞异常触发前消息处于uack状态,但同时观察到收到了一个manual ack。
在这里插入图片描述
(1)当代码继续执行,抛出MessageConversionException,会向MQ发送reject,删除消息。

这里发生了一个有意思的现象,因为我消息阻塞了太久触发了MQ消息重新投递,因此又出现了一个manual ack以及交替出现的ready和unack。
在这里插入图片描述

(2)当抛出异常是RuntimeException,可以观察到unack一直是1,且一直尝试重新投递。(重新投递没有触发那个自动的manual ack)
在这里插入图片描述

这里留两个小问题:为什么会自动发送了一个manual ack?这个重传是否是超时重传还是什么其他机制?

3、设置acknowledge-mode为manual,修改消费者端代码手动调用api返回消息回执

@RabbitListener(bindings = @QueueBinding(key="*.top",value = @Queue(value="df.topic.queue1"),exchange = @Exchange(value = "df.topic1", type = ExchangeTypes.TOPIC)
))
public void listenDirectQueue1(Object msg, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) throws IOException {System.out.println("这是第" + (cnt++) + "条消息");channel.basicAck(deliveryTag, false);
}

(1)测试ack
首先是接着2的调试代码继续调试【也就是此时消息队列中有一个消息没有被接收】,所以启动测试代码后这个消息会被重新投递,消息被消费者接收后手动回复确定,整个过程如下图
在这里插入图片描述
接下来重新投递一条消息观察正常的手动ack全过程,图中上面的图蓝色线(unacked)被红色线遮挡,它们其实是同样的走势。也就是当消息成功投递到消费者,会触发一次自动的ack(Deliver manual ack),但是消息处于uack,等到业务代码完成手动进行ack后该消息被ack并且删除。
在这里插入图片描述
(2)测试nack

@RabbitListener(bindings = @QueueBinding(key="*.top",value = @Queue(value="df.topic.queue1"),exchange = @Exchange(value = "df.topic1", type = ExchangeTypes.TOPIC)
))
public void listenDirectQueue1(Object msg, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) throws IOException {try {System.out.println("这是第" + (cnt++) + "条消息");throw new BusinessException();
//            channel.basicAck(deliveryTag, false);}catch (BusinessException e){// nack且重新入队 重新推送channel.basicNack(deliveryTag, false, true);}catch (MessageConversionException e){// reject 并且不重新入队channel.basicReject(deliveryTag, false);}
}

上面的代码抛出了自定义的业务异常,这个异常会被捕获并且返回nack,然后重新推送,如下图
在这里插入图片描述
(3)测试reject

@RabbitListener(bindings = @QueueBinding(key="*.top",value = @Queue(value="df.topic.queue1"),exchange = @Exchange(value = "df.topic1", type = ExchangeTypes.TOPIC)
))
public void listenDirectQueue1(Object msg, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) throws IOException {try {System.out.println("这是第" + (cnt++) + "条消息");throw new MessageConversionException("just a test for msg reject");
//            channel.basicAck(deliveryTag, false);}catch (MessageConversionException e){// reject 并且不重新入队channel.basicReject(deliveryTag, false);}}

这里抛出MessageConversionException,捕获后手动返回拒绝并且不重新投递,过程如下
在这里插入图片描述
**总结:**实际上SpringAMQP只是提供了三个接口basicAckbasicNackbasicReject,这三个接口何时触发,基于何种规则触发都是可以自定义的,上面的三个实现是基本与acknowledge-mode: auto一样的逻辑:业务异常nack且重新投递、消息异常reject且不重新投递、正常接收和消费则ack

消息失败重试机制


在这里插入图片描述

上面提到的两个小问题

为什么会触发一次自动的Deliver(Manual ACK)

原来这个Deliver(Manual ACK)是一个投递事件ACK,当消息进入消息队列未被消费,其状态为ready,当其被投递到消费者,状态会更新为unacked,如果被成功消费并且确认,则会被删除。
当首次投递,则会触发一个投递事件(ready变为unacked)
当消息被重新投递,不会再触发投递事件
这是因为:

  1. 性能优化:重复发送投递事件会导致网络带宽浪费、Broker的CPU浪费、监控系统负载
  2. 语义精确性:RabbitMQ的事件新系统旨在“报告状态变化的边界,而非状态本身”,重复投递的状态变化是首次投递的重复,因此没有必要重复报告
  3. 避免误导性监控:重复报告投递事件会导致消息计数错误,无法区分实际新消息以及重新投递消息

这个重传是否是超时重传还是什么其他机制?

明天再补了

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

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

相关文章

P3 QT项目----记事本(3.4)

3.4 文件选择对话框 QFileDialog 3.4.1 QFileDialog 开发流程 使用 QFileDialog 的基本步骤通常如下: 实例化 :首先,创建一个 QFileDialog 对象的实例。 QFileDialog qFileDialog;设置模式 :根据需要设置对话框的模式&…

学习笔记(26):线性代数-张量的降维求和,简单示例

学习笔记(26):线性代数-张量的降维求和,简单示例 1.先理解 “轴(Axis)” 的含义 张量的 “轴” 可以理解为 维度的方向索引 。对于形状为 (2, 3, 4) 的张量,3 个轴的含义是: 轴 0(axis0&…

健康档案实训室:构建全周期健康管理的数据基石

一、健康档案实训室建设背景 随着“健康中国2030”战略深入推进,健康档案作为居民健康数据的核心载体,在疾病预防、慢性病管理、医疗决策等领域的价值日益凸显。在此背景下,健康档案实训室建设成为职业院校对接政策要求、培养专业健康管理…

【MATLAB第119期】基于MATLAB的KRR多输入多输出全局敏感性分析模型运用(无目标函数,考虑代理模型)

【MATLAB第119期】基于MATLAB的KRR多输入多输出全局敏感性分析模型运用(无目标函数,考虑代理模型) 下一期研究SHAP的多输入多输出敏感性分析方法 一、SOBOL(无目标函数) (1)针对简单线性数据…

Linux常用文件目录命令

浏览目录命令: ls 、pwd目录操作命令:cd、mkdir、rmdir浏览文件命令:cat、more、less、head、tail文件操作命令:cp、rm、mv、find、grep、tar 浏览目录命令 ls ◼ 命令名称:ls ◼ 命令英文原意:list ◼ …

PIN码vs密码,电脑登录的快捷键你用对了吗?

你是否也遇到过这样的窘境:信心满满地输入电脑开机密码,屏幕却无情地提示“密码错误”。仔细一看,才发现登录界面悄悄地变成了要求输入“PIN码”。这种因为混淆了PIN码和账户密码而导致的开机失败,相信不少朋友都碰到过。 PIN码作…

【大模型科普】AIGC技术发展与应用实践(一文读懂AIGC)

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈人工智能与大模型应用 ⌋ ⌋ ⌋ 人工智能(AI)通过算法模拟人类智能,利用机器学习、深度学习等技术驱动医疗、金融等领域的智能化。大模型是千亿参数的深度神经网络(如ChatGPT&…

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…

XXE漏洞知识

目录 1.XXE简介与危害 XML概念 XML与HTML的区别 1.pom.xml 主要作用 2.web.xml 3.mybatis 2.XXE概念与危害 案例:文件读取(需要Apache >5.4版本) 案例:内网探测(鸡肋) 案例:执行命…

02-性能方案设计

需求分析与测试设计 根据具体的性能测试需求,确定测试类型,以及压测的模块(web/mysql/redis/系统整体)前期要与相关人员充分沟通,初步确定压测方案及具体的性能指标QA完成性能测试设计后,需产出测试方案文档发送邮件到项目组&…

STL优先级队列的比较函数与大堆小堆的关系

STL中的priority_queue&#xff08;优先级队列&#xff09;通过比较函数来确定元素的优先级顺序&#xff0c;从而决定其内部是形成大堆还是小堆。以下是关键点总结&#xff1a; 默认行为与大堆&#xff1a; 默认情况下&#xff0c;priority_queue使用std::less<T>作为比较…

React---day11

14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store&#xff1a; 我们在使用异步的时候理应是要使用中间件的&#xff0c;但是configureStore 已经自动集成了 redux-thunk&#xff0c;注意action里面要返回函数 import { configureS…

OD 算法题 B卷【反转每对括号间的子串】

文章目录 反转每对括号间的子串 反转每对括号间的子串 给出一个字符串s&#xff0c; 仅含有小写英文字母和英文括号’(’ ‘)’&#xff1b;按照从括号内到外的顺序&#xff0c;逐层反转每对括号中的字符串&#xff0c;并返回最终的结果&#xff1b;结果中不能包含任何括号&am…

如何做好一份技术文档?从规划到实践的完整指南

如何做好一份技术文档&#xff1f;从规划到实践的完整指南 &#x1f31f; 嗨&#xff0c;我是IRpickstars&#xff01; &#x1f30c; 总有一行代码&#xff0c;能点亮万千星辰。 &#x1f50d; 在技术的宇宙中&#xff0c;我愿做永不停歇的探索者。 ✨ 用代码丈量世界&…

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…

详细讲解Flutter GetX的使用

Flutter GetX 框架详解&#xff1a;状态管理、路由与依赖注入 GetX 是 Flutter 生态中一款强大且轻量级的全功能框架&#xff0c;集成了状态管理、路由管理和依赖注入三大核心功能。其设计理念是简洁高效&#xff0c;通过最小的代码实现最大的功能&#xff0c;特别适合快速开发…

【大模型:知识库管理】--Dify接入RAGFlow 知识库

ragflow的官方文档&#xff1a; HTTP API 接口 |抹布流 --- HTTP API | RAGFlow 接着前文&#xff0c;我们已经创建了知识库&#xff0c;那么如何才能使用它呢&#xff1f; 当然也是通过网络API的形式去调用它。本文将讲解两种方式&#xff1a; Dify调用python源码调用 目录…

Vue 模板配置项深度解析

Vue 模板配置项深度解析 在 Vue 组件开发中&#xff0c;template 是定义组件视图结构的核心配置项。作为 Vue 专家&#xff0c;我将全面解析模板的各个方面&#xff0c;帮助你掌握高效构建 Vue 组件的艺术。 一、模板基础概念 1. 模板的本质 声明式渲染&#xff1a;描述 UI…

基于深度哈希与图索引的十亿级图像近重复检测系统

引言 在上一篇文章中,我们介绍了基于Vision API和SimHash的亿级图像去重方案。本文将更进一步,探讨如何应对十亿级图像库的近重复检测挑战,提出一种结合深度哈希学习与图索引的创新架构。该系统在多个关键指标上比传统方法提升显著: 检测精度提升:mAP@100达到0.92(传统方…

Python开发基础手语识别(基础框架版)

一、前期准备 想要实现这些&#xff0c;首先就是要模拟出来一个大致的框架&#xff0c;方便后续开展&#xff0c;下面的就是随便写的一个框架&#xff0c;大家凑合看看就行&#xff0c;基本上是这个意思&#xff1a; from tkinter import *w Tk() w.title("手语识别&am…