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.mfbz.cn/a/879745.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux内核结构

Linux内核结构 文章目录 Linux内核结构一、Linux内核结构介绍1.1 总体结构:1.2 Linux内核结构框图: 二、图解Linux系统架构三、shell3.1 shell的含义:3.2 shell的作用:3.3 shell的类型:3.4 shell的使用:3.5…

安泰电压放大器设计方法是什么样的

电压放大器是电子领域中常用的设备,用于将低电压信号放大成高电压信号。电压放大器在信号处理、通信系统、仪器测量、控制系统、医疗设备和研究和实验室等领域都有着广泛的应用。 电压放大器的设计方法主要包括选择合适的放大器拓扑结构、选择适当的放大器参数以及进…

72v-80V降5V1.5A恒压降压WT6035

72v-80V降5V1.5A恒压降压WT6035 WT6035 是一款高压降压开关稳压器,可用于将 72V - 80V 的电压降为 5V、1.5A 的恒压输出,以下是一些关于它的特点及应用注意事项: 芯片特点: 宽电压输入范围:输入电压范围为 5V 至 100V…

设计模式之命令模式:从原理到实战,深入解析及源码应用

🎯 设计模式专栏,持续更新中 欢迎订阅:JAVA实现设计模式 🛠️ 希望小伙伴们一键三连,有问题私信都会回复,或者在评论区直接发言 命令模式 什么是命令模式? 命令模式(Command Pattern…

sensitive-word 敏感词 v0.20.0 数字全部匹配,而不是部分匹配

敏感词系列 sensitive-word-admin 敏感词控台 v1.2.0 版本开源 sensitive-word-admin v1.3.0 发布 如何支持分布式部署? 01-开源敏感词工具入门使用 02-如何实现一个敏感词工具?违禁词实现思路梳理 03-敏感词之 StopWord 停止词优化与特殊符号 04-…

《微信小程序实战(3) · 推广海报制作》

📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗 🌻 CSDN入驻不久,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数…

VISIA 皮肤检测

费用:自费158元 不能医保报销 先清洁肌肤,然后做一个皮肤检测. 1200万像素高清摄像头,一个白光,一个偏正光,还有一个紫外光,三种模式,分析面部情况. 8张图 反应皮肤情况应用: 在医美前和医美一次修复完成后,皮肤情况对比. 数值越高 越好 斑点图: 皱纹图: 分数比较低的话,皮肤…

SpringBoot教程(三十) | SpringBoot集成Shiro(权限框架)

SpringBoot教程(三十) | SpringBoot集成Shiro(权限框架) 一、 什么是Shiro二、Shiro 组件核心组件其他组件 三、流程说明shiro的运行流程 四、SpringBoot 集成 Shiro1. 添加 Shiro 相关 maven2. 添加 其他 maven3. 设计数据库表4.…

268页PPT大型集团智慧工厂信息化顶层架构设计(2024版)

智能制造装备是高端制造业的关键,通过整合智能传感、控制、AI等技术,具备了信息感知、分析规划等智能化功能,能显著提升加工质量、效率和降低成本。该装备是先进制造、信息、智能技术的深度融合。其原理主要包括物联网集成、大数据分析与人工…

【数据结构与算法 | 灵神题单 | 合并链表篇】力扣2, 21, 445, 2816

1. 力扣2:两数相加 1.1 题目: 给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。 请你将两个数相加,并以相同形式返回一个表示和的链表。 你可…

黑神话悟空mac可以玩吗

黑神话悟空mac上能不能玩对于苹果玩家来说很重要,那么黑神话悟空mac可以玩吗?目前是玩不了了,没有针对ios系统的版本,只能之后在云平台上找找了,大家可以再观望下看看。 黑神话悟空mac可以玩吗 ‌使用CrossOver‌&…

JavaEE初阶——初识EE(Java诞生背景,CPU详解)

阿华代码,不是逆风,就是我疯,你们的点赞收藏是我前进最大的动力!!希望本文内容能帮到你! 目录 零:Java的发展背景介绍 一:EE的概念 二:计算机的构成 1:CU…

TCP 拥塞控制:一场网络数据的交通故事

从前有条“高速公路”,我们叫它互联网,而这条公路上的车辆,则是数据包。你可以把 TCP(传输控制协议)想象成一位交通警察,负责管理这些车辆的行驶速度,以防止交通堵塞——也就是网络拥塞。 第一…

你知道企业架构中核心的4大架构联系和不同吗?

引言:企业架构是指对企业信息管理系统中具有体系的、普遍性的问题而提供的通用解决方案它是基于业务导向和驱动的架构来理解、分析、设计、构建、集成、扩展、运行和管理信息统的。复杂系统是基于架构(或体系)的集成,而不是基于部件(或组件)的集成。指导…

【ARM】中断的处理

ARM的异常向量表 如果发生异常后并没有exception level切换,并且发生异常之 前使用的栈指针是SP_EL0,那么使用第一组异常向量表。如果发生异常后并没有exception level切换,并且发生异常之 前使用的栈指针是SP_EL1/2/3,那么使用第…

支付宝开发者✖️「蚂小财」——AgentUniverse专业多智能体框架在严谨产业中的应用实践

正在直播:点击进入直播间互动拿蚂蚁保温杯 直播 

英飞凌最新AURIX™TC4x芯片介绍

概述: 英飞凌推出最新的AURIX™TC4x系列,突破了电动汽车、ADAS、汽车e/e架构和边缘应用人工智能(AI)的界限。这一代面向未来的微控制器将有助于克服安全可靠的处理性能和效率方面的限制。客户将可缩短快速上市时间并降低整体系统成本。为何它被称为汽车市场新出现的主要颠覆…

828华为云征文 | 华为云Flexusx与Docker技术融合,打造个性化WizNote服务

前言 华为云Flexus X实例携手Docker技术,创新融合打造高效个性化WizNote服务。华为云Flexus X实例的柔性算力与Docker的容器化优势相结合,实现资源灵活配置与性能优化,助力企业轻松构建稳定、高效的云端笔记平台。828华为云企业上云节特惠来袭…

[2025]医院健康陪诊系统(源码+定制+服务)

博主介绍: ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台…

Element UI入门笔记(个人向)

Element UI入门笔记 将页面分割为一级菜单、二级菜单、导航栏三个部分;使用npm下载安装,使用语句npm i element-ui -s; 布局组件 el-form 用于创建和管理表单;从属性上看: :model:用于双向数据绑定,将表单…