RabbitMQ 高级特性——持久化

在这里插入图片描述

文章目录

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

前言

前面我们学习了 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.rhkb.cn/news/427590.html

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

相关文章

Delphi5利用DLL实现窗体的重用

文章目录 效果图参考利用DLL实现窗体的重用步骤1 设计出理想窗体步骤2 编写一个用户输出的函数或过程,在其中对窗体进行创建使它实例化步骤3 对工程文件进行相应的修改以适应DLL格式的需要步骤4 编译工程文件生成DLL文件步骤5 在需要该窗体的其他应用程序中重用该窗…

不会JS逆向也能高效结合Scrapy与Selenium实现爬虫抓取

1. 创建基础的scrapy项目 1.1 基础项目 在pycharm中安装scrapy框架 pip install scrapy 创建项目 scrapy startproject 项目名称 我们现在可以看到整体文件的目录: firstBlood ├── firstBlood # 项目跟目录 │ ├── init.py │ ├── items.py # 封装数…

【网络】高级IO——select版本TCP服务器

目录 前言 一,select函数 1.1.参数一:nfds 1.2.参数二: readfds, writefds, exceptfds 1.2.1.fd_set类型和相关操作宏 1.2.2.readfds, writefds, exceptfds 1.2.3.怎么理解 readfds, writefds, exceptfds是输入输出型参数 1.3.参数三…

数据结构之二叉树遍历

二叉树的遍历 先序遍历 先输入父节点,再遍历左子树和右子树:A、B、D、E、C、F、G 中序遍历 先遍历左子树,再输出父节点,再遍历右子树:D、B、E、A、F、C、G 后序遍历 先遍历左子树,再遍历右子树,…

SpringBoot设置mysql的ssl连接

因工作需要,mysql连接需要开启ssl认证,本文主要讲述客户端如何配置ssl连接。 开发环境信息: SpringBoot: 2.0.5.RELEASE mysql-connector-java: 8.0.18 mysql version:8.0.18 一、检查服务端是否开启ssl认…

微信公众号开发入门

微信公众号开发是指开发者基于微信公众平台(WeChat Official Accounts Platform)所提供的接口与功能,开发和构建自定义的功能与服务,以满足企业、组织或个人在微信生态中的应用需求。微信公众号开发主要围绕公众号消息处理、菜单管…

K1计划100%收购 MariaDB; TDSQL成为腾讯云核心战略产品; Oracle@AWS/Google/Azure发布

重要更新 1. 腾讯全球数字生态大会与9月5日-6日举行,发布“5T”战略,包括TDSQL、TencentOS、TCE(专有云 )、TBDS(大数据)、TI (人工智能开发平台)等 ( [2] ) ; 并正式向原子开源基金…

初始分布式系统和Redis特点(

(一)认识redis Redis是一个开源(BSD许可),内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理。它支持字符串、哈希表、列表、集合、有序集合,位图,hyperlog…

后台数据管理系统 - 项目架构设计-Vue3+axios+Element-plus(0920)

十三、文章分类页面 - [element-plus 表格] Git仓库:https://gitee.com/msyycn/vue3-hei-ma.git 基本架子 - PageContainer 功能需求说明: 基本架子-PageContainer封装文章分类渲染 & loading处理文章分类添加编辑[element-plus弹层]文章分类删除…

[Python]案例驱动最佳入门:Python数据可视化在气候研究中的应用

在全球气候问题日益受到关注的今天,气温变化成为了科学家、政府、公众讨论的热门话题。然而,全球气温究竟是如何变化的?我们能通过数据洞察到哪些趋势?本文将通过真实模拟的气温数据,结合Python数据分析和可视化技术&a…

Flutter启动无法运行热重载

当出现这种报错时,大概率是flutter的NO_Proxy出问题。 请忽略上面的Android报错因为我做的是windows开发这个也就不管了哈,解决下面也有解决报错的命令大家执行一下就行。 着重说一下Proxy的问题, 我们看到提示NO_PROXY 没有设置。 这个时候我…

基于YOLOv8+LSTM的商超扶梯场景下行人安全行为姿态检测识别

基于YOLOv8LSTM的商超扶梯场景下行人安全行为姿态检测识别 手扶电梯 行为识别 可检测有人正常行走,有人 跌倒,有人逆行三种行为 跌倒检测 电梯跌倒 扶梯跌倒 人体行为检测 YOLOv8LSTM。 基于YOLOv8LSTM的商超扶梯场景下行人安全行为姿态检测识别&#xf…

Vue3.0组合式API:使用ref获取DOM元素

Vue3.0组合式API系列文章: 《Vue3.0组合式API:setup()函数》 《Vue3.0组合式API:使用reactive()、ref()创建响应式代理对象》 《Vue3.0组合式API:computed计算属性、watch监听器、watchEffect高级监听器》 《Vue3.0组合式API&…

【贪心算法】贪心算法一

贪心算法一 1.柠檬水找零2.将数组和减半的最少操作次数3.最大数4.摆动序列 点赞👍👍收藏🌟🌟关注💖💖 你的支持是对我最大的鼓励,我们一起努力吧!😃😃 1.柠檬水找零 题目…

【Linux】【Vim】Vim 基础

Vim/Gvim 基础 文本编辑基础编辑操作符命令和位移改变文本重复改动Visual 模式移动文本(复制、粘贴)文本对象替换模式 光标移动以 word 为单位移动行首和行尾行内指定单字符移动到匹配的括号光标移动到指定行滚屏简单查找 /string标记 分屏vimdiff 文本编辑 基础编辑 Normal 模…

Gitlab runner的使用示例(二):Maven + Docker 自动化构建与部署

Gitlab runner的使用示例(二):Maven Docker 自动化构建与部署 在本篇文章中,我们将详细解析一个典型的 GitLab CI/CD 配置文件(gitlab-ci.yml),该文件主要用于通过 Maven 构建 Java 应用&…

07_Python数据类型_集合

Python的基础数据类型 数值类型:整数、浮点数、复数、布尔字符串容器类型:列表、元祖、字典、集合 集合 集合(set)是Python中一个非常强大的数据类型,它存储的是一组无序且不重复的元素,集合中的元素必须…

Games101学习 - 着色

本文主要讲述Games101中的着色部分。 文中将使用UE的UTexture2D接口,若不了解可以看这篇: https://blog.csdn.net/grayrail/article/details/142165442 1.面积比计算三角形坐标 通过三角形面积比可以得到三角形的坐标alpha、beta、gamma从而进行插值&a…

AI技术好书推荐:《AI系统-原理与架构》

今年1月份在B站发现了一个B站宝藏博主,发布的一系列AI技术类科普视频内容很干,逻辑清晰,很多知识点讲的深入浅出,非常有用,被直接种粉。 后来这一系列的课程内容博主有了出书的计划,机缘巧合有幸参与部分章…

CSS入门笔记

目录 概述 组成 CSS 语法 常见的使用方式 CSS 优先级 CSS 选择器 1. 基本选择器 2. 属性选择器 3. 伪类选择器 4. 组合选择器 示例 优先级 边框样式与盒子模型 单个边框 边框轮廓(Outline) 盒子模型 模型介绍 边距设置 布局示例 文…