RabbitMQ 高级特性——持久化

news2024/12/22 23:37:16

在这里插入图片描述

文章目录

  • 前言
  • 持久化
    • 交换机持久化
    • 队列持久化
    • 消息持久化

前言

前面我们学习了 RabbitMQ 的高级特性——消息确认,消息确认可以保证消息传输过程的稳定性,但是在保证了消息传输过程的稳定性之后,还存在着其他的问题,我们都知道消息都存放在 RabbtiMQ Broker 中的队列中的,如果我们的 RabbitMQ Server 发生了重启或者宕机了,那么我们内存中的队列也就丢失了,相信大家也应该知道如何解决这种问题,对了,那就是持久化。

持久化

RabbitMQ 的持久化分为三个部分:交换机的持久化、队列的持久化和消息的持久化。

交换机持久化

交换机的持久化是我们在声明交换机的时候,将 durable 的参数设置为 true 实现的。也就是将交换机的内部属性在服务器的内部保存,当 MQ 服务器发生重启之后,不需要去重新建立交换机,交换机会根据服务器中保存的交换机的属性来自动创建。

如果交换机不设置持久化,那么当 RabbitMQ 服务重启之后,交换机的元数据就会丢失,那么要想再使用这个交换机就只能重新创建这个交换机。

在这里插入图片描述

对于我们之前设置的持久化的交换机,如果我们重启 RabbitMQ Server,看一下这些交换机是否还会存在:

重启 RabbitMQ Server:systemctl restart rabbitmq-server.service

在这里插入图片描述

可以发现这些设置了持久化的交换机在 RabbitMQ Server 重启之后还是存在的,也不能说是存在,只是重启的时候自动创建了,那么我们再来看看未被设置为持久化的队列在 RabbitMQ Server 重启之后是否会自动创建:

@Bean("noPermanentExchange")
public TopicExchange noPermanentExchange() {
    return ExchangeBuilder.topicExchange(Constants.NO_PERMANENT_EXCHANGE).durable(false).build();
}

启动一下程序,创建这个交换机:

在这里插入图片描述
然后重启一下 RabbitMQ Server:

在这里插入图片描述
重启服务之后,我们创建的非持久化的交换机就不会自动创建了。

队列持久化

队列的持久化也是我们在声明队列的时候设置 durable 的参数来实现的。如果队列不设置持久化,那么当我们的 RabbitMQ Server 重启的时候,这些未设置持久化的队列就会丢失,那么队列中的消息也就会丢失(不管队列里面的消失是否设置了持久化)。

队列的持久化能保证队列的元数据不会因异常情况而丢失,但是并不能保证内部所存储的消息不会丢失,要确保消息不会丢失,还需要设置消息为持久化。

QueueBuilder.durable(Constants.ACK_QUEUE).build(); 创建持久化队列;
QueueBuilder.nonDurable(Constants.ACK_QUEUE).build(); 创建非持久化队列,durable 参数默认是 true,也就是队列默认是持久化的队列。

消息持久化

实现消息持久化,需要把消息的投递模式(MessageProperties 中的 deliveryMode)设置为2,也就是 MessageDeliveryMode.PERSISTENT。

public enum MessageDeliveryMode {
	NON_PERSISTENT,//非持久化
	PERSISTENT;//持久化
}

消息存储在队列中,既然存储在队列中,那么要想真正实现消息的持久化,就也需要保证队列的持久化。如果队列不持久化,消息持久化,那么当 RabbitMQ 服务重启的时候,队列就会消息,更不用说里面的消息了,当队列持久化,但是消息不持久化的话,那么服务重启,队列存在但是队列中的消息不存在,也就是说只有队列和消息都设置为持久化才能真正实现消息的持久化。

public static final String PERMANENT_EXCHANGE = "permanent.exchange";
public static final String PERMANENT_QUEUE = "permanent.queue";

声明队列、交换机以及队列和交换机的绑定关系:

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

@Bean("permanentExchange")
public TopicExchange permanentExchange() {
    return ExchangeBuilder.topicExchange(Constants.PERMANENT_EXCHANGE).build();
}

@Bean("permanentBinding")
public Binding permanentBinding(@Qualifier("permanentExchange") Exchange exchange, @Qualifier("permanentQueue") Queue queue) {
    return BindingBuilder.bind(queue).to(exchange).with("permanent").noargs();
}

注意:当进行队列和交换机的绑定的时候,如果参数中交换机的类型是 Exchange 的话,创建的 Binding 实例中就还需要加上 noargs 方法。

生产者代码:

@RequestMapping("/permanent")
public String permanent() {
    String msg = "rabbitmq permanent";
    Message message = new Message(msg.getBytes(),new MessageProperties());
    message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
    rabbitTemplate.convertAndSend(Constants.PERMANENT_EXCHANGE,"permanent",message);
    return "消息发送成功";
}

我们先不实现消费者,这里只是为了看队列中的消息是否实现了持久化。

我们先向队列中生产几条消息,然后再重启服务,看当队列和消息都设置为持久化的时候是否能真正实现消息的持久化:

在这里插入图片描述
然后重启 RabbitMQ 服务:

在这里插入图片描述
重启之后发现,队列中的消息还是存在的,那么如果我们将队列设置为非持久化,消息设置为持久化呢?

因为 RabibtMQ 交换机和队列只要创建了那么就不能修改它的属性了,所以我们这里先将之前创建的队列删除重新创建:

@Bean("permanentQueue")
public Queue permanentQueue() {
    return QueueBuilder.nonDurable(Constants.PERMANENT_QUEUE).build();
}

在这里插入图片描述

重启服务:

注意当我们重启 RabbitMQ 的时候,需要将我们的程序也关闭掉,不然当我们重启 RabbitMQ 服务的时候,程序就会自动连接上 RabbitMQ 然后自动创建交换机和队列:

我们的程序首先会报错:

在这里插入图片描述
然后服务重启成功之后,就会自动连接 RabbitMQ 并且创建交换机和队列:

在这里插入图片描述
在这里插入图片描述
所以我们生产完成几条消息之后,关闭程序然后重启服务:

在这里插入图片描述
重启服务之后:

在这里插入图片描述
可以看到我们的队列没有实现持久化,整个队列都没了,更别说队列里面的消息了,所以只有队列和消息都实现持久化的时候才能真正实现消息的持久化。

实现消息的持久化的时候,不能将全部的消息都持久化,因为写硬盘的速度是非常慢的,我们应该按需按情况实现部分消息的持久化。

将交换机、队列和消息实现持久化就能百分百保证数据不丢失了吗?答案是否定的。

  1. 从消费者来说,如果在订阅消费队列时将 autoAck 设置为 true,那么当消费者接收到相关的消息之后,还没来得及处理就宕机了,这样也算数据丢失,这种情况很好解决,就是将 autoAck 设置为 false,手动确认就好了
  2. 在持久化的消息正确存入 RabbitMQ 之后,还需要一段时间(虽然很短,但是也不能忽视)才能存入磁盘中,RabbitMQ 并不会为每条消息都进行同步存盘(调用内核的 fsync 方法)的处理,可能仅仅保存到操作系统的缓存之中,而不是物理磁盘上,如果在这个时间段内 RabbitMQ 发生了宕机、重启等异常,那么消息还没来得及落盘,那么这些消息就会丢失

那么第二个问题如何解决呢?

  1. 引入RabbitMQ的仲裁队列(后面再讲),如果主节点(master)在此特殊时间内挂掉,可以自动切换到从节点(slave),这样有效地保证了高可用性。除非整个集群都挂掉(此方法也不能保证100%可靠,但是配置了仲裁队列要比没有配置仲裁队列的可靠性要高很多。实际生产环境中的关键业务队列一般都会设置仲裁队列)。
  2. 还可以在发送端引入事务机制或者发送方确认机制来确保消息已经正确地发送并存储至RabbitMQ中。详细参考下一个章节内容介绍——“发送方确认”。

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

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

相关文章

【rpg像素角色】俯视角-行走动画

制作像素角色的俯视角行走动画并不像看上去那么复杂,尤其是在你已经完成了角色的4个方向站立姿势之后(其中左右方向可以通过水平翻转实现)。接下来,我会一步步为你讲解如何制作行走动画。 1. 理解行走规律 在制作行走动画之前&am…

Spring Boot集成Akka Stream快速入门Demo

1.什么是Akka Stream? Akka Streams是一个用于处理和传输元素序列的库。它建立在Akka Actors之上,使流的摄入和处理变得简单。由于它是建立在Akka Actors之上的,它为Akka现有的actor模型提供了一个更高层次的抽象。Akka流由3个主要部分组成-…

从0开始学习RocketMQ:快速部署启动

快速部署 快速部署一个单节点单副本 RocketMQ 服务,并完成简单的消息收发。 安装Apache RocketMQ 下载地址:RocketMQ官网下载 这里我们下载二进制包:rocketmq-all-5.3.0-bin-release.zip 直接解压即可:tar -zxvf rocketmq-all…

光伏开发:工商业光伏的流程管理全面解析

一、项目准备阶段 1、资源寻觅与沟通 首要任务是寻找适合的工商业屋顶或空地资源,并与业主初步交流,了解其意向、屋顶条件及用电情况。这一阶段的关键在于建立信任关系,为后续工作奠定基础。 2、资料收集与核查 全面收集业主资料&#xff…

算法练习题26——多项式输出(模拟)

输入格式 输入共有 2 行 第一行 1 个整数,n,表示一元多项式的次数。 第二行有 n1 个整数,其中第 i 个整数表示第 n−i1 次项的系数,每两个整数之间用空格隔开。 输出格式 输出共 1 行,按题目所述格式输出多项式。…

Navicat BI 中创建自定义字段:计算字段

在数据库设计和开发中,避免存储任何可以从其他字段计算或重建的数据是一种惯例。因此,在 Navicat BI 中构建图表时,你可能会缺少一些数据。但这不是问题,因为 Navicat BI 提供了专门用于此目的的计算字段。在今天的博客中&#xf…

网站按钮检测系统源码分享

网站按钮检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vis…

浅谈MVC设计模式

1 前言 1.1 内容概要 熟悉使用JSON工具,完成Java对象(Map)和Json字符串之间的相互转换(注意提供构造器和getter/setter方法) 注意事项:不管使用的是什么JSON工具,都要提供类的无参构造方法和…

基于SpringBoot的宠物寄领养网站管理系统

作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【前后端分离】基于JavaSpringBootVueMySQL的宠物寄领养网站…

北斗卫星系统信号介绍

覆盖范围亚太区域全球范围 卫星数量35颗区域服务卫星30颗全球服务卫星 信号频段B1I, B2IB1C, B2a, B3, 兼容GPS/Galileo 定位精度区域内10米全球2.5~5米,中国内更高 新增功能区域短报文通信全球短报文通信、星基增强、精密定位 抗干扰能力相对有限更强 互操作…

无人机 PX4 飞控 | 如何检测状态估计EKF性能

无人机 PX4 飞控 | 如何检测状态估计EKF性能 前言检查EKF性能缺少pyulog问题解决脚本崩溃没有输出文件生成对应文件 结语 前言 ECL (Estimation and Control Library,估计和控制库),其中的状态估计使用扩展卡尔曼滤波算法&#x…

图像检测【YOLOv5】——深度学习

Anaconda的安装配置:(Anaconda是一个开源的Python发行版本,包括Conda、Python以及很多安装好的工具包,比如:numpy,pandas等,其中conda是一个开源包和环境管理器,可以用于在同一个电脑…

计算机网络基本概述

欢迎大家订阅【计算机网络】学习专栏,开启你的计算机网络学习之旅! 文章目录 前言一、网络的基本概念二、集线器、交换机和路由器三、互连网与互联网四、网络的类型五、互连网的组成1. 边缘部分2. 核心部分 六、网络协议 前言 计算机网络是现代信息社会…

安装node 报错需要:glibc >= 2.28

--> 解决依赖关系完成 错误:软件包:2:nodejs-18.20.4-1nodesource.x86_64 (nodesource-nodejs) 需要:libm.so.6(GLIBC_2.27)(64bit) 错误:软件包:2:nodejs-18.20.4-1nodesource.x86_64 (nodesource-nodej…

【数据结构篇】~排序(1)之插入排序

排序~插入排序 前言插入排序1.直接插入排序(时间复杂度:O(N^2))1.思想2.代码 2.希尔排序(时间复杂度:O(N∙))1.思路简易证明希尔排序的复杂度 2.代码 前言 四大排序,今天解决插入排序 堆排序和冒泡排序已经写过了&am…

C++笔记---继承(上)

1. 继承的简单介绍 1.1 继承的概念 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许我们在保持原有类特性的基础上进行扩展,增加方法(成员函数)和属性(成员变量),这样产生新的类,称派生类。 继承呈…

如何利用 Smarter Balanced 塑造教育领域的 AI 治理

目录 定义挑战 以人为本的设计引领 融入多样性 探索以学生为中心的价值观 探索效果的层次和不同的影响 部位于加利福尼亚州的Smarter Balanced Assessment Consortium 是一个由会员主导的公共组织,为 K-12 和高等教育领域的教育工作者提供评估系统。该组织成立…

09_Tensorflow2图像处理大赏:让你的图片笑出AI感,惊艳朋友圈!

1. 图像处理案例 1.1 逆时针旋转90度 import tensorflow as tf import matplotlib.pyplot as plt import matplotlib.cm as cm import numpy import osdef show_pic(pic,name,cmapNone):显示图像plt.imshow(pic,cmapcmap) plt.axis(off) # 打开坐标轴为 on # 设置图像标题…

C语言数据类型、变量及数据类型的长度、取值范围

文章目录 一、数据类型介绍1.字符型2.整型3.浮点型4.布尔类型 二、变量1.变量的创建2.变量的分类 三、数据类型的长度(字节)1.sizeof 操作符2.各种数据类型的长度3.sizeof中表达式不计算 四、各种类型的取值范围1.signed和unsigned2.数据类型的取值范围 五、整型提升练习1练习2…

【Obsidian】当笔记接入AI,Copilot插件推荐

当笔记接入AI,Copilot插件推荐 自己的知识库笔记如果增加AI功能会怎样?AI的回答完全基于你自己的知识库余料,是不是很有趣。在插件库中有Copilot插件这款插件,可以实现这个梦想。 一、什么是Copilot? 我们知道githu…