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

RabbitMQ08_保证消息可靠性

保证消息可靠性

        • 一、生产者可靠性
          • 1、生产者重连机制(防止网络波动)
          • 2、生产者确认机制
            • Publisher Return 确认机制
            • Publisher Confirm 确认机制
        • 二、MQ 可靠性
          • 1、数据持久化
            • 交换机、队列持久化
            • 消息持久化
          • 2、Lazy Queue 惰性队列
        • 三、消费者可靠性
          • 1、消费者确认机制
          • 2、失败重试机制
          • 3、业务幂等性

一、生产者可靠性
1、生产者重连机制(防止网络波动)
spring:rabbitmq:connection-timeout: 1s #设置MQ的连接超时时间template:retry:enabled: true #开启超时重试机制(默认是false)initial-interval: 1000ms #失败后的初始等待时间multiplier: 1 #失败后下次的等待时长倍数,下次等待时长= initial-interval * multipliermax-attempts: 3 #最大重试次数
2、生产者确认机制
Publisher Return 确认机制

消息投递到MQ但是MQ路由失败,MQ返回路由失败原因

spring:rabbitmq:publisher-returns: true # 开启publisher return机制
@Slf4j
@AllArgsConstructor
@Configuration
public class MqConfig {private final RabbitTemplate rabbitTemplate;@PostConstructpublic void init(){rabbitTemplate.setReturnsCallback(new RabbitTemplate.ReturnsCallback() {@Overridepublic void returnedMessage(ReturnedMessage returned) {log.error("触发return callback,");log.debug("exchange: {}", returned.getExchange());log.debug("routingKey: {}", returned.getRoutingKey());log.debug("message: {}", returned.getMessage());log.debug("replyCode: {}", returned.getReplyCode());log.debug("replyText: {}", returned.getReplyText());}});}
}
Publisher Confirm 确认机制

临时消息投递到了MQ且入队成功,返回ACK
持久消息投递到了MQ且入队完成持久化,返回ACK
消息投递异常,返回NACK

spring:rabbitmq:publisher-confirm-type: correlated # 开启publisher confirm机制,并设置confirm类型

publisher-confirm-type 的三种类型

  • none 关闭confirm机制
  • simple 同步阻塞等待MQ回执消息
  • correlated MQ异步回调返回回执消息
@Test
void testPublisherConfirm() throws InterruptedException {CorrelationData cd = new CorrelationData();cd.getFuture().addCallback(new ListenableFutureCallback<CorrelationData.Confirm>() {        @Overridepublic void onFailure(Throwable ex) {// Future发生异常时的处理逻辑,基本不会触发log.error("handle message ack fail", ex);}@Overridepublic void onSuccess(CorrelationData.Confirm result) {// Future接收到回执的处理逻辑,参数中的result就是回执内容if(result.isAck()){ log.debug("发送消息成功,收到 ack!");} else {log.error("发送消息失败,收到 nack, reason : {}", result.getReason());//TODO 重试发送}}});// 3.发送消息rabbitTemplate.convertAndSend("hmall.direct", "red1", "hello", cd);
}
二、MQ 可靠性
1、数据持久化
交换机、队列持久化

默认创建时就是持久化的(Durability = Durable)

在这里插入图片描述

消息持久化

RabbitTemplate 的 convertAndSend() 方法发送的消息默认就是持久化的(delivery mode = 2)

如果非要发送一个非持久化的消息,需要在调用 rabbitTemplate.convertAndSend() 方法时,显式地设置消息的 MessageProperties,并将 deliveryMode 设置为 1 (非持久化)

2、Lazy Queue 惰性队列

Lazy Queue是一种以惰性模式运行的队列,它尽可能地将消息存储在磁盘上,而不是内存中。只有当消费者需要消费消息时,这些消息才会被加载到内存中,效率比传统队列高。

3.12版本后,所有队列都是Lazy Queue模式,无法更改。

三、消费者可靠性
1、消费者确认机制

消费者回执消息类型

  • ack 消费者处理成功,RabbitMQ 将从队列中删除消息
  • nack 消费者处理失败,RabbitMQ 需再次投递消息
  • reject 消费者拒绝处理,RabbitMQ 将从队列中删除消息

SpringAMQP 消息监听器的三种确认模式

  • none 不处理。即消费者收到消息后立刻返回ack,消息会丢失,非常不安全。
  • manual 手动模式。业务代码手动调用api发送 ack 或 reject,存在业务入侵,但更灵活。
  • auto 自动模式(默认)。通过 AOP 对消息处理方法做环绕增强,正常返回ack,出现业务异常返回nack,出现消息处理或校验异常返回reject
spring:rabbitmq:listener:simple:acknowledge-mode: auto
2、失败重试机制

消费者处理消息出现异常时利用本地重试,而不是无限的requeue到mq,让mq重新投递给消费者

spring:rabbitmq:listener:simple:retry:enabled: true # 开启消费者失败重试(默认是关闭的)initial-interval: 1000ms # 初始的失败等待时长为1秒multiplier: 1 # 下次失败的等待时长倍数,下次等待时长 = multiplier * last-intervalmax-attempts: 3 # 最大重试次数stateless: true # true无状态;false有状态。如果业务中包含事务,这里改为false

开启重试模式后,重试次数耗尽,如果消息依然失败,则需要有MessageRecoverer接口来处理,它包含三种不同的实现。

失败消息处理策略

  • RejectAndDontRequeueRecoverer:默认实现,重试耗尽后直接reject,丢弃消息。
  • ImmediateRequeueMessageRecoverer:重试耗尽后返回nack,消息重新入队
  • RepublishMessageRecoverer:重试耗尽后将失败消息投递到指定的交换机

以第三种失败消息处理策略为例,配置方式如下:

@Bean
public MessageRecoverer republishMessageRecoverer(RabbitTemplate rabbitTemplate) {return new RepublishMessageRecoverer(rabbitTemplate, "error.direct", "error");
}
3、业务幂等性

由于存在各种确认和重试机制,消费者有重复消费消息的可能性,因此要保证业务的幂等性。
保证业务幂等性的方式如下:

  • 方案一:发送消息时生成唯一消息ID,投递给消费者,消费者接收到消息,业务处理成功后将消息ID保存到数据库,下次根据消息ID去数据库查询判断是否已处理,如果已处理则放弃处理。
@Bean
public MessageConverter messageConverter(){// 1.定义消息转换器Jackson2JsonMessageConverter jjmc = new Jackson2JsonMessageConverter();// 2.配置自动创建消息id,用于识别不同消息,也可以在业务中基于ID判断是否是重复消息jjmc.setCreateMessageIds(true);return jjmc;
}
  • 方案二:结合业务逻辑,基于业务本身做判断。

相关文章:

  • 2、在LVGL模拟器中了解部件的基础属性
  • 智慧城市主要运营模式分析
  • 【后端开发】JavaEE初阶——计算机是如何工作的???
  • 常见的TTL,RS232,RS485,IIC,SPI,UART之间的联系和区别
  • YOLOv8 Flask整合问题
  • 什么是Agent智能体?
  • 2024年信息安全企业CRM选型与应用研究报告
  • 探索 Android DataBinding:实现数据与视图的完美融合
  • 中间件:maxwell、canal
  • SpinalHDL之语义(Semantic)(一)
  • Python办公自动化案例:将Excel数据批量保存到Word表格中
  • spring boot启动报错:so that it conforms to the canonical names requirements
  • 验收测试:从需求到交付的全程把控!
  • 从自身经历浅谈对于C++/Java的认识
  • HttpServletRequestWrapper这个类有什么作用?
  • [Vue CLI 3] 配置解析之 css.extract
  • Fundebug计费标准解释:事件数是如何定义的?
  • java概述
  • mysql innodb 索引使用指南
  • Python实现BT种子转化为磁力链接【实战】
  • SpringCloud集成分布式事务LCN (一)
  • Spring框架之我见(三)——IOC、AOP
  • 从PHP迁移至Golang - 基础篇
  • 等保2.0 | 几维安全发布等保检测、等保加固专版 加速企业等保合规
  • 订阅Forge Viewer所有的事件
  • - 概述 - 《设计模式(极简c++版)》
  • 高性能JavaScript阅读简记(三)
  • 函数式编程与面向对象编程[4]:Scala的类型关联Type Alias
  • 排序算法学习笔记
  • 思维导图—你不知道的JavaScript中卷
  • 微信小程序:实现悬浮返回和分享按钮
  • 问题之ssh中Host key verification failed的解决
  • RDS-Mysql 物理备份恢复到本地数据库上
  • !!【OpenCV学习】计算两幅图像的重叠区域
  • #Js篇:单线程模式同步任务异步任务任务队列事件循环setTimeout() setInterval()
  • #我与Java虚拟机的故事#连载19:等我技术变强了,我会去看你的 ​
  • #在 README.md 中生成项目目录结构
  • (12)Linux 常见的三种进程状态
  • (C语言)求出1,2,5三个数不同个数组合为100的组合个数
  • (Redis使用系列) Springboot 在redis中使用BloomFilter布隆过滤器机制 六
  • (超详细)2-YOLOV5改进-添加SimAM注意力机制
  • (附源码)SSM环卫人员管理平台 计算机毕设36412
  • (接口自动化)Python3操作MySQL数据库
  • (力扣记录)1448. 统计二叉树中好节点的数目
  • (十八)用JAVA编写MP3解码器——迷你播放器
  • (万字长文)Spring的核心知识尽揽其中
  • (一)SvelteKit教程:hello world
  • (轉貼) UML中文FAQ (OO) (UML)
  • .net core docker部署教程和细节问题
  • .net core 控制台应用程序读取配置文件app.config
  • .Net Core 微服务之Consul(二)-集群搭建
  • .NET Core日志内容详解,详解不同日志级别的区别和有关日志记录的实用工具和第三方库详解与示例
  • .net framwork4.6操作MySQL报错Character set ‘utf8mb3‘ is not supported 解决方法
  • .NET MVC第三章、三种传值方式
  • .NetCore+vue3上传图片 Multipart body length limit 16384 exceeded.