【RabbitMQ 实战】10 消息持久化和存储原理

一、持久化

1.1 持久化对象

rabbitmq的持久化分为三个部分:

  • 交换器的持久化。
  • 队列的持久化。
  • 消息的持久化。

1.1.1 交换器持久化

  • 交换器的持久化是通过在声明交换器时, 指定Durability参数为durable实现的。
  • 若交换器不设置持久化,在rabbitmq服务重启之后,相关的交换器元数据会丢失,但消息不会丢失,只是不能将消息发送到这个交换器中。
    所以在声明交换器时,都要设置持久化。
  • 在web监控创建时,默认也是持久化模式,指定持久化模式带有标识“D”。
    在这里插入图片描述
    springboot监听器,实现交换器持久化示例
    在这里插入图片描述

1.1.2 队列持久化

  • 队列的持久化是通过在声明队列时, 指定Durability参数为durable实现的。
  • 若队列不设置持久化,在rabbitmq服务重启之后,相关队列的元数据和消息数据同时丢失。
  • 若队列设置持久化,只能保证队列本身的元数据不会因异常情况而丢失,但是并不能保证内部所存储的消息不会丢失。要确保消息不会丢失,需要将消息设置为持久化
  • 在web监控创建时,默认也是持久化模式,指定持久化模式带有标识“D”。
    在这里插入图片描述
    springboot监听器,实现队列持久化示例
    在这里插入图片描述

1.1.3 消息持久化

消息的持久化可以通过消息的投递模式来实现,属于代码层面上的。可以控制每一条消息是否久化。
但是将所有消息都设置为持久化,会严重影响rabbitmq服务器性能,写入磁盘的速度比写入内存的速度慢得不只一点点。所以对于可靠性不是那么高的消息可以不采用持久化处理以提高整体的吞吐量。在选择是否要将消息持久化时,需要在可靠性和吐吞量之间做一个权衡。
在这里插入图片描述
springboot代码设置消息的持久化示例
在这里插入图片描述

1.2 总结要点

  • 交换器、队列、消息都可以设置是否持久化。交换器和队列持久化的含义是元数据持久化。消息持久化的含义是消息本身持久化。

将交换器、队列、消息都设置了持久化之后能百分之百保证数据不丢失吗?答案是不能

  • 从消费者来说,如果在订阅消费队列时将 autoAck 参数设置为 true,那么当消费者接收到相关消息之后,还没来得及处理就宕机了,这样也算数据丢失。这种情况很好解决,将autoAck 参数设置为 false,并进行手动确认。
  • 在持久化的消息正确存入rabbitmq之后,还需要有一段时间(虽然很短,但是不可忽视) 才能存入磁盘之中。如果在这段时间内rabbitmq服务节点发生了宕机、重启等异常情况,消息保存还没来得及落盘,那么这些消息将会丢失。这种情况可以使用镜像队列来解决。

二、存储机制

前面提到的消息持久化,其实是在rabbitmq的“持久层”中完成的。不管是持久化的消息,还是非持久化的消息都可以被写入到磁盘。

  • 持久化的消息在到达队列时就入盘,而且还可以设置持久化的消息在内存中也保存一份备份,这么做可以提高业务效率,当内存吃紧时会从内存中清除。
  • 非持久化的消息一般只保存在内存中,在内存吃紧的时候会被换入到磁盘中,以节省内存空间。

2.1 存储方式

持久层是一个逻辑上的概念,实际包含两个部分:

  • 队列索引 (rabbit_queue_index):负责维护队列中落盘消息的信息,包括消息的存储地点、消息在队列中的位置、是否已被交付给消费者、是否已被消费者 ack 等。每个队列都有与之对应的一个队列索引。
  • 消息存储(rabbit_msg_store):而消息存储是以键值对的形式存储消息,它被所有队列共享,所以在每个节点中有且只有一个。从技术层面上来说,rabbit_msg_store 具体还可以分两类:
    • msg_store_persistent :负责持久化消息的持久化,重启后消息不会丢失。
    • msg_store_transient:负责非持久化消息的持久化,重启后消息会丢失。
      我们一般说消息存储,是习惯性地将 msg_store_persistent 和 msg_store_transient 看成 rabbit_msg_store 一个整体。
I have no name!@ed73deb9f1c5:/bitnami/rabbitmq/mnesia/rabbit@stats/msg_stores/vhosts/9PIHRMVSJH6VBOR100H7141ZT$ ls -al
drwxr-xr-x. 2 1001 root   19 Oct  7 02:57 msg_store_persistent
drwxr-xr-x. 2 1001 root   19 Oct  7 02:57 msg_store_transient
  • 存在队列索引里的好处?
    性能上的优化。相比存在消息存储里,直接存在队列索引仅需进行一次写操作。而存储在消息存储中的消息则需要两次写操,先写一次索引,再写一次消息存储,因此会有一定的性能提升。
    注意事项:
  • 若消息直接存在队列索引中,则当消息通过exchange同时路由到多个队列时,此消息会被写到每个队列的索引文件中。
  • 若消息是存在消息存储中,就仅仅只有一个副本。

2.2 存储文件

  • 上面提到的消息,是包括消息体属性headers,可以直接存储在队列索引中,也可以保存在消息存储中。
  • rabbitmq启动后,会针对每个vhost会启动两个进程:msg_store_persistent和msg_store_transient,这两个进程作为服务端负责将消息写入文件,从文件读取消息。
    • msg_store_persistent负责将持久化消息写入文件与从文件中读取消息。
    • msg_store_transient负责非持久化消息写入文件与从文件中读取消息。
  • 默认存储文件位置:通过日志可以看到存储文件地址,包含queues、msg_store_persistent、msg_store_transient 这3个文件夹。如下图,我这里是指定了存储文件地址。
I have no name!@ed73deb9f1c5:/bitnami/rabbitmq/mnesia/rabbit@stats/msg_stores/vhosts/9PIHRMVSJH6VBOR100H7141ZT$ ls -al
total 16
drwxr-xr-x. 5 1001 root  125 Oct  7 02:57 .
drwxr-xr-x. 4 1001 root   72 Oct  7 01:15 ..
-rw-r--r--. 1 1001 root   83 Oct  7 01:15 .config
drwxr-xr-x. 2 1001 root   19 Oct  7 02:57 msg_store_persistent
drwxr-xr-x. 2 1001 root   19 Oct  7 02:57 msg_store_transient
drwxr-xr-x. 3 1001 root   38 Oct  7 01:18 queues
-rw-r--r--. 1 1001 root 5464 Oct  7 02:57 recovery.dets
-rw-r--r--. 1 1001 root    9 Oct  7 02:57 .vhost

上面的地址/bitnami/rabbitmq/mnesia/rabbit@stats,是队列的数据存放目录,这个在在哪里找呢,可以通过日志来查看,如下图所示:
在这里插入图片描述
日志中还显示了,9PIHRMVSJH6VBOR100H7141ZT这个目录,对应着virtual01这个vhost的目录。对于rabbitmq来说,每一个租户vhost的消息存储,都是放在不同的目录的
在这里插入图片描述

2.2.1 队列索引.idx文件

rabbit_queue_index 中以顺序(文件名从 0 开始累加) 的段文件来进行存储,后缀为“ .idx "。

每个段文件中包含定的 SEGMENT_ENTRY_COUNT 条记录,SEGMENT_ENTRY_COUNT 默认值为16384字节。
每个rabbit_queue_index 从磁盘中读取消息的时候至少要在内存中维护一个段文件,所以设置queue_index_embed_msgs_below参数指定阈值大小时要格外谨慎,一点点增大也可能会引起内存爆炸式的增长。

2.2.2 消息存储.rdq文件

经过 rabbit_msg_store 处理的所有消息都会以追加的方式写入到文件中,当一个文件的大小超过指定的限制 (file_size_lmit)后,关闭这个文件再创建一个新的文件以供新的消息写入,文件后缀是“ .rdq ”。
文件名从0开始进行累加,所以文件名最小的文件也是最老的文件。
如下所示0.rdq文件

I have no name!@ed73deb9f1c5:/bitnami/rabbitmq/mnesia/rabbit@stats/msg_stores/vhosts/628WB79CIFDYO9LJI6DKMI09L/msg_store_persistent$ ls -al
total 0
drwxr-xr-x. 2 1001 root  19 Oct  7 02:57 .
drwxr-xr-x. 4 1001 root 111 Oct  7 02:57 ..
-rw-r--r--. 1 1001 root   0 Oct  7 02:57 0.rdq

在进行消息的存储时,rabbitmq会在ETS (Erlang Term Storage) 表中记录消息在文件中的位置映射 (Index) 和文件的相关信息 (FileSummary)。

  • 读取文件信息:
    • 在读取消息的时候,先根据消息的 ID (msg_id)找到对应存储的文件。
    • 若文件存在并且未被锁住,则直接打开文件,从指定位置读取消息的内容。
    • 若文件不存在,或被锁住,则发送请求由 rabbit_msg_store 进行处理。
  • 删除文件信息:
  • 消息的删除只是从 ETS 表删除指定消息的相关信息,同时更新消息对应的存储文件的相关信息。
  • 执行消息删除操作时,不会立即对在文件中的消息进行删除,先是标记为垃圾数据。
    • 若一个文件中都是垃圾数据时,则删除文件。
    • 若一个文件中存在有效数据,则触发垃圾回收机制,进行文件合并选择性删除。
  • 垃圾回收文件合并机制:
    • 当检测到前后两个文件中的有效数据可以合并在一个文件中,并且所有的垃圾数据的大小和所有文件(至少有3 个文件存在的情况下)的数据大小的比值超过设置的值 GARBAGE_ERACTION (默认值为 0.5) 时,才会触发垃圾回收将两个文件合并。

2.2.3 垃圾回收机制(文件合并)

文件合并前提:
执行合并的两个文件一定是逻辑上相邻的两个文件。
文件合并流程:

  • 第一步,执行合并时首先锁定这两个文件。
  • 第二步,先对前面文件中的有效数据进行整理。
  • 第三步,再将后面文件的有效数据写入到前面的文件。
  • 第四步,更新消息在 ETS 表中的记录。
  • 第五步,最后删除后面的文件。

2.3 存储原理

  • 从3.5.0版本开始,较小的消息是直接存储在队列索引.rdx中。
  • 较大的消息存在.rdq队列文件中

如下图所示,我发布的消息,消息比较小时,在0.idx中,即存在索引中
下面是通过查看0.idx,发现里面有消息的正文内容
在这里插入图片描述
当消息体比较大时,存放的是rdq文件时面
在这里插入图片描述

  • 在进行消息的存储时,rabbitmq会在ETS表中记录消息在文件中的映射,以及文件的相关信息。
  • 消息读取时,根据消息ID找到该消息所存储的文件,在文件中的偏移量,然后打开文件进行读取。
  • 消息的删除只是从ETC表删除指定消息的相关信息,同时更新消息对应存储的文件的相关信息(更新文件有效数据大小)。

2.3.1 生产者消息写入原理

每个队列则看成是一个客户端,当生产者发送的消息达到队列时,向服务端请求写,写入过程如下:

  • 第一步,rabbitmq启动后,针对每个vhost开启两个进程,msg_store_persistent进程和msg_store_transient进程。两进程作为服务端,每个队列作为客户端。
  • 第二步,当生产者发送消息到队列时,每个队列都会向两进程发起写入请求。
  • 第三步,两进程开始往磁盘里写入消息。
    • msg_store_persistent进程将持久化消息写入到服务器的msg_store_persistent目录下,文件名称依次为0.rdq、1.rdq、2.rdq等等。
    • msg_store_transient进程将非持久化消息写入到服务器的msg_store_transient目录下,文件名称依次为0.rdq、1.rdq、2.rdq等等。
      在这里插入图片描述

2.3.2 消费者消息读取原理

  • 第一步,消费者向队列获取消息体。
  • 第二步,队列汇聚消息ID去找落盘文件。
    • 若文件存在,且未被锁住,则直接读取文件内容,返回消息给消费者。
    • 若文件不存在,或已被锁住,则让rabbit_msg_store进程处理。
  • 第三步,队列向两进程发起请求,进程先是通过GC进程去查看文件是否被锁住,同时也会清理垃圾,进行有效数据合并。
    • 若被锁住则解锁,获取消息,返回给消费者。
    • 若清理垃圾后,发现还是没有此消息,则向rabbitmq其他节点发送询问请求。
  • 第四步,其他节点会根据消息ID挨个寻找,直至将rabbitmq集群每个节点找遍,之后返回结果给消费者。

在这里插入图片描述

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

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

相关文章

c语言:通讯录管理系统(文件版本)

前言:在大多数高校内,都是通过设计一个通讯录管理系统来作为c语言课程设计,通过一个具体的系统设计将我们学习过的结构体和函数等知识糅合起来,可以很好的锻炼学生的编程思维,本文旨在为通讯录管理系统的设计提供思路和…

将nginx注册为Windows系统服务

文章目录 1、使用nssm小工具2、使用winsw小工具2.1、下载2.2、用法2.3、重命名2.4、创建配置文件2.4.1、xml文件2.4.2、config文件(该文件可省略) 2.5、最终文件2.6、安装与卸载 1、使用nssm小工具 该方法最简单 首先,下载nssm小工具&#…

HTML5+CSSDAY4综合案例一--热词

样式展示图&#xff1a; 代码如下&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>热词…

docker 基本操作

一、docker 概述 Docker是一个开源的应用容器引擎&#xff0c;基于go语言开发并遵循了apache2.0协议开源。 Docker是在Linux容器里运行应用的开源工具&#xff0c;是一种轻量级的“虚拟机”。 Docker 的容器技术可以在一台主机上轻松为任何应用创建一个轻量级的、可移植的、自…

HomeView/主页 的实现

1. 创建数据模型 1.1 创建货币模型 CoinModel.swift import Foundation// GoinGecko API info /*URL:https://api.coingecko.com/api/v3/coins/markets?vs_currencyusd&ordermarket_cap_desc&per_page250&page1&sparklinetrue&price_change_percentage24…

机器人制作开源方案 | 齿轮传动轴偏心轮摇杆简易四足

1. 功能描述 齿轮传动轴偏心轮摇杆简易四足机器人是一种基于齿轮传动和偏心轮摇杆原理的简易四足机器人。它的设计原理通常如下&#xff1a; ① 齿轮传动&#xff1a;通过不同大小的齿轮传动&#xff0c;实现机器人四条腿的运动。通常采用轮式齿轮传动或者行星齿轮传动&#xf…

Blender:使用立方体制作动漫头像

好久没水文章 排名都掉到1w外了 ~_~ 学习一下blender&#xff0c;看能不能学习一点曲面变形的思路 一些快捷键 ctrl 空格&#xff1a;区域最大化&#xff0c;就是全屏 ctrl alt 空格&#xff1a;也是区域最大化 shift b&#xff1a;框选区域然后最大化显示该范围 shift 空…

3.springcloudalibaba gateway项目搭建

文章目录 前言一、搭建gateway项目1.1 pom配置1.2 新增配置如下 二、新增server服务2.1 pom配置2.2新增测试接口如下 三、测试验证3.1 分别启动两个服务&#xff0c;查看nacos是否注册成功3.2 测试 总结 前言 前面已经完成了springcloudalibaba项目搭建&#xff0c;接下来搭建…

AI如何帮助Salesforce从业者找工作?

在当今竞争激烈的就业市场中&#xff0c;找到满意的工作是一项艰巨的任务。成千上万的候选人竞争一个岗位&#xff0c;你需要利用一切优势从求职大军中脱颖而出。 这就是AI的用武之地&#xff0c;特别是像ChatGPT这样的人工智能工具&#xff0c;可以成为你的秘密武器。本篇文章…

【Windows】RPC调用过程实例详解

概述&#xff1a;windows 创建 RPC调用过程实例详解 参考文章&#xff1a;Remote procedure call (RPC)&#xff08;远程过程调用 (RPC)&#xff09; - Win32 apps | Microsoft Learn 文章目录 0x01、生成 UUID 和模版(IDL)文件0x02、添加 acf 文件0x03、编译 idl 文件0x04、客…

Vuex基础使用存取值+异步请求后台

目录 一、Vuex简介 1.1 定义 1.2 Vuex关键概念 1.3 使用Vuex的优势 1.4 Vuex中各个js文件的用途 1.5 Vuex各组件 1.5.1 图解 1.5.2 详解 1.6 变量传值的演变形式 二、Vuex获取值 2.1 安装 2.2 菜单栏 2.3 模块 2.4 引用 三、Vuex改变值 四、Vuex异步&请求后台…

ACK 云原生 AI 套件:云原生 AI 工程化落地最优路径

作者&#xff1a;胡玉瑜(稚柳) 前言 在过去几年中&#xff0c;人工智能技术取得了突飞猛进的发展&#xff0c;涵盖了机器学习、深度学习和神经网络等关键技术的重大突破&#xff0c;这使得人工智能在各个领域都得到广泛应用&#xff0c;对各行各业产生了深远的影响。 特别值…

计算机视觉处理的开源框架

计算机视觉是一门涉及图像和视频分析的领域&#xff0c;有许多开源的框架和库可用于构建计算机视觉应用程序。以下是一些常见的计算机视觉开源框架及其特点&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合…

地级市HVV | 未授权访问合集

在网站前后端分离盛行下&#xff0c;将大部分权限控制交给前端&#xff0c;导致js中隐藏未授权或者可绕过的前端鉴权。前后端分离的好处是提高开发效率&#xff0c;同时防止黑客更直接的对服务器造成危害&#xff0c;但权限控制的工作量全部交给前端会导致大量页面未授权或者后…

Flink---12、状态后端(HashMapStateBackend/RocksDB)、如何选择正确的状态后端

星光下的赶路人star的个人主页 大鹏一日同风起&#xff0c;扶摇直上九万里 文章目录 1、状态后端&#xff08;State Backends&#xff09;1.1 状态后端的分类&#xff08;HashMapStateBackend/RocksDB&#xff09;1.2 如何选择正确的状态后端1.3 状态后端的配置 1、状态后端&am…

香港专用服务器拥有良好的国际网络连接

香港服务器在多个领域有着广泛的应用。无论是电子商务、金融交易、游戏娱乐还是社交媒体等&#xff0c;香港服务器都能够提供高效稳定的服务。对于跨境电商来说&#xff0c;搭建香港服务器可以更好地满足亚洲用户的购物需求&#xff1b;对于金融机构来说&#xff0c;香港服务器…

力扣第98题 验证二叉搜索树 c++ 与上一篇文章相似

题目 98. 验证二叉搜索树 中等 相关标签 树 深度优先搜索 二叉搜索树 二叉树 给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下&#xff1a; 节点的左子树只包含 小于 当前节点的数。节点的右子树只包含 大于 当…

如何在小程序中设置导航栏文字颜色和背景颜色

不同商家有不同的颜色风格&#xff0c;例如有些做设计的公司&#xff0c;主要是黑色风格&#xff1b;有些卖珠宝的商家&#xff0c;主要是金色风格&#xff1b;他们的小程序&#xff0c;也需要进行同样的风格设定。下面具体介绍怎么在小程序中进行整个风格设定。 1. 在小程序管…

Gooxi国鑫搭载第四代英特尔至强可扩展处理器系列服务器焕新登场

由算力驱动的数字经济渗透到了百行千业&#xff0c;在驱动传统经济转型升级和效能优化的同时&#xff0c;也大幅度增加了各行业数据处理能力的需求 。 面对千行百业加速创新应用和AIGC时代像潮水一样奔涌算力需求&#xff0c;得益于第四代英特尔至强可扩展处理器以及基于Gooxi最…

MySQL之MHA高可用配置及故障切换实例

MySQL之MHA高可用配置及故障切换实例 1、MHA概述1.1MHA 是什么1.2、MHA 的组成1.3MHA 的特点 2、MHA搭建准备2.1实验思路2.2实验准备 3、MHA搭建的步骤3.1配置主从复制3.2安装 MHA 软件3.3故障模拟 1、MHA概述 1.1MHA 是什么 MHA&#xff08;MasterHigh Availability&#xf…