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

【RabbitMQ 实战】11 队列的结构和惰性队列

一、 队列的结构

队列的组成:

  • 队列由 rabbit_amgqueue_process 和 backing_queue两部分组成。
  • rabbit_amqqueue_process负责协议相关的消息处理,即接收生产者发布的消息、向消费者交付消息、处理消息的确认 (包括生产端的 confirm 和消费端的 ack) 等。
  • backing_queue是消息存储的具体形式和引擎,并向rabbit_amqqueue_process提供相关的接口以供调用。
    消息投递:
  • 若消息投递的目的队列是空的,并且有消费者订阅了此队列,则该消息直接发给消费者,不经过队列。
  • 若消息无法直接投递给消费者时,需要暂时将消息存入队列,以便重新投递。消息存入队列后,会随着系统的负载在队列中不断地流动,消息的状态会不断发生变化。

1.1 消息状态分类

消息的4 种状态:

  • alpha状态:表示消息内容 (包括消息体、属性和 headers) 和消息索引都存储在内存中。
  • beta状态:表示消息内容保存在磁盘中,消息索引保存在内存中。
  • gamma状态:表示消息内容保存在磁盘中,消息索引在磁盘和内存中都有。
  • delta状态:表示消息内容和索引都在磁盘中。

注意事项:

  • 对于持久化的消息,消息内容和消息索引都必须先保存在磁盘上,才会处于上述状态中的一种。
  • gamma 状态的消息是只有持久化的消息才会有的状态。

1.2 消息状态对资源影响

rabbitmq在运行时,会根据统计的消息传送速度,定期计算一个当前内存中能够保存的最大消息数量(target_ram_count)。

  • 若alpha 状态的消息数量大于此值时,就会引起消息的状态转换,多余的消息可能会转换到beta 状态、gamma 状态或者 delta 状态。
  • 区分这 4 种状态的主要作用是满足不同的内存和CPU需求。

消息状态对服务器资源的影响:

  • alpha状态最耗内存,但很少消耗 CPU。
  • delta状态基本不消耗内存,但是需要消耗更多的 CPU 和磁盘 I/O 操作。

注意事项:

  • delta 状态需要执行两次I/O 操作才能读取到消息。一次是读消息索引 (从 rabbit_queue_index 中),一次是读消息内容(从 rabbit_msg_store 中)。
  • beta 和 gamma 状态都只需要一次I/0 操作就可以读取到消息 (从 rabbit_msg_store中)。

1.3 队列中的消息状态分布结构

  • 对于普通的没有设置优先级和镜像的队列来说,backing_queue的默认实现是rabbit_variable_queue。其内部通过 5 个子队列 Q1、Q2、Delta、Q3 和 Q4 来体现消息的各个状态。
  • 整个队列包括rabbit_amgqueue_process和backing_queue 的各个子队列。
  • 队列中的消息状态结构分布:
    • Q1、Q4 只包含 alpha 状态的消息。也就是消息体和消息索引都在内存中的消息。
    • Q2 、Q3 包含 beta 和gamma 状态的消息,
    • Delta 只包含 delta 状态的消息。也就是消息内容和索引都在磁盘中的消息。
  • 队列中的消息流动状态变化:
    • 一般情况下,消息按照 Q1——> Q2——> Delta——> Q3——> Q4 顺序进行流动,但并不是每一条消息都一定会经历所有的状态,这个取决于当前系统的负载状况。
    • 从Q1至Q4的过程,就相当于消息内存——> 磁盘——> 内存的过程。
      • 当队列负载高,占用极大的内存时,可以把一部分消息放入磁盘,以此节省内存空间。
      • 当队列负载降低,内存资源释放出来时,这部分消息又渐渐回到内存被消费者获取,使得整个队列具有很好的弹性。
        在这里插入图片描述

1.4 消费者对队列中消息状态的影响变化

消费消息对队列中的消息状态变化流程:

  • 第一步:当消费者获取消息时,首先会从 Q4 中获取内存中消息,如果获取成功则返回。
    若Q4为空,则尝试从 Q3 中获取消息,进入第二步。
  • 第二步:从Q3中获取消息时,系统首先会判断Q3是否为空,如果为空则返回队列为空,即此时队列中无消息。
    若Q3不为空,则取出 Q3 中的消息并和Delta中的消息长度做已判断。如果Q3和Delta都为空,则可以认为 Q2、Delta、03、Q4 全部为空,此时将Q1中的消息直接转移至 Q4,下次直接从Q4 中获取消息。
    若Q3为空,Delta 不为空,则将 Delta 的消息转移至Q3中,下次可以直接从Q3中获取消息。
  • 第三步:在将消息从 Delta 转移到 Q3 的过程中,是按照索引分段读取的,首先读取某一段,然后判断读取的消息的个数与Delta 中消息的个数是否相等,如果相等,则可以判定此时 Delta 中已无消息,则直接将Q2 和刚读取到的消息一并放入到 Q3 中;如果不相等,仅将此次读取到的消息转移到 Q3。

结论:

  • 通常在负载正常时,如果消息被消费的速度不小于接收新消息的速度,对于不需要保证可靠不丢失的消息来说,极有可能只会处于 alpha 状态。
  • 对于 durable 属性设置为 true 的消息一定会进入 gamma 状态,并且在开启 publisher confirm机制时,只有到了 gamma 状态时才会确认该消息已被接收。
  • 若消息消费速度足够快、内存也充足,这些消息也不会继续走到下一个状态。

影响及应对措施:

  • 在系统负载较高时,已接收到的消息若不能很快被消费掉,这些消息就会进入到很深的队列中去,这样会增加处理每个消息的平均开销。因为要花更多的时间和资源处理“堆积”的消息,如此用来处理新流入的消息的能力就会降低,使得后流入的消息又被积压到很深的队列中继续增大处理每个消息的平均开销,继而情况变得越来越恶化,使得系统的处理能力大大降低。
  • 应对这一问题一般有 3 种措施:
    • 增加 prefetch_count值,即一次发送多条消息给消费者,加快消息被消费的速度。这个值跟消息分发有关,开发人员代码中使用设置。
    • 采用 multiple ack,降低处理 ack 带来的开销。可以回顾消费端的确认机制,也是开发人员设置。
    • 流量控制。

二、惰性队列

当生产者将消息发送到RabbitMQ的时候,队列中的消息会尽可能地存储在内存之中,这样可以更加快速地将消息发送给消费者。即使是持久化的消息,在被写入磁盘的同时也会在内存中驻留一份备份。当RabbitMQ需要释放内存的时候,会将内存中的消息换页至磁盘中,这个操作会耗费较长的时间。
惰性队列会将收到的消息直接存入文件系统中,而不管是持久化的或者是非持久化的。这样减少了内存的消耗,但是会增加I/O的使用,如果消息是持久化的,那么这样的I/O操作不可避免。
注意如果惰性队列中存储的是非持久化的消息,内存的使用率会一直很稳定,但是重启后消息一样会丢失。
代码设置惰性队列

在队列声明的时候可以通过x-queue-mode 参数来设置队列的模式,取值为default和lazy。下面示例演示了一个惰性队列的声明细节:

Map<String,Object> args = new HashMap<String,Object>();
args.put( "x-queue-mode" , "lazy");
channel.queueDeclare( "myqueue" , false , false , false , args);

对应的Policy 设置方式为:

rabbitmqctl set_policy Lazy "^myqueue$ " ' {"queue-mode ":" lazy" } ' --apply-to-queues

如果要将普通队列转换为隋性队列,那么我们需要忍受性能损耗,需要将缓存中的消息转存到磁盘中,然后才能接收新的消息。反之,将一个惰性队列转为普通队列,会将磁盘中的消息批量地导入到内存中。

相关文章:

【RabbitMQ 实战】11 队列的结构和惰性队列

一、 队列的结构 队列的组成&#xff1a; 队列由 rabbit_amgqueue_process 和 backing_queue两部分组成。rabbit_amqqueue_process负责协议相关的消息处理&#xff0c;即接收生产者发布的消息、向消费者交付消息、处理消息的确认 (包括生产端的 confirm 和消费端的 ack) 等。…...

Python3-批量重命名指定目录中的一组文件,更改其扩展名

Python3-批量重命名指定目录中的一组文件&#xff0c;更改其扩展名 1.argparse模块2.vars内置函数3.os.listdir(path)4.os.path.splitext(filepath)5.os.path.join6.os.rename7.os.path.isfile8.批量重命名指定目录中的一组文件&#xff0c;更改其扩展名 1.argparse模块 argpa…...

渗透测试KAILI系统的安装环境(第八课)

KAILI系统的安装环境(第八课) Kaili是一款基于PHP7的高性能微服务框架&#xff0c;其核心思想是面向服务的架构&#xff08;SOA&#xff09;&#xff0c;支持http、websocket、tcp等多种通信协议&#xff0c;同时还提供了RPC、Service Mesh、OAuth2等功能。Kaili框架非常适合构…...

如何正确方便的理解双指针?力扣102 (二叉树的层序遍历)

双指针&#xff0c;顾名思义就是指针的指针。 在此之前我们需要先理解单指针 &#xff08;简称为指针&#xff09;。指针很简单&#xff0c;直接上例子&#xff1a;例&#xff1a;现有两个变量&#xff0c;a10,b20. 要求&#xff1a;交换他们的值&#xff0c;输出的结果应为a20…...

Vue或uniapp引入自定义字体

一、为什么引入字体 对于大部分APP或网站而言&#xff0c;字体是很重要的一部分。在前端开发中&#xff0c;选用合适的字体往往会极大地提升网站的视觉体验。然而&#xff0c;网页中默认字体的种类和风格有限&#xff0c;且在不同的设备、浏览器上渲染效果不尽相同。因此&…...

​力扣:LCR 122. 路径加密​ 题目:剑指Offer 05.替换空格(c++)

本文章代码以c为例&#xff01; 力扣&#xff1a;LCR 122. 路径加密 题目&#xff1a; 代码&#xff1a; class Solution { public:string pathEncryption(string path) {for(int i0;i<path.size();i){if(path[i].){path[i] ;}}return path;} }; 难度升级&#xff08;原…...

cJson堆内存释放问题

cJSON_Delete()&#xff0c;是用来释放json对象的&#xff0c;释放父JSON对象后&#xff0c;子JSON对象也会被释放。 CJSON_free()&#xff0c;是用来释放其他对象的。 int main(void) {cJSON* cjson_test NULL;cJSON* cjson_address NULL;cJSON* cjson_skill NULL;char* s…...

论文阅读/写作扫盲

第一节&#xff1a;期刊科普 JCR分区和中科院分区是用于对期刊进行分类和评估的两种常见方法。它们的存在是为了帮助学术界和研究人员更好地了解期刊的学术质量、影响力和地位。 JCR分区&#xff08;Journal Citation Reports&#xff09;&#xff1a;JCR分区是由Clarivate Ana…...

一文拿捏对象内存布局及JMM(JAVA内存模型)

1 JMM(Java Memory Model) 1 概述 Java内存模型(Java Memory Model简称JMM)是一种抽象的概念&#xff0c;并不真实存在&#xff0c;它描述的一组规则或者规范。通过这些规则、规范定义了程序中各个变量的访问方式。jvm运行的程序的实体是线程&#xff0c;而每个线程运行时&am…...

Android组件通信——ActivityGroup(二十五)

1. ActivityGroup 1.1 知识点 &#xff08;1&#xff09;了解ActivityGroup的作用&#xff1b; &#xff08;2&#xff09;使用ActivityGroup进行复杂标签菜单的实现&#xff1b; &#xff08;3&#xff09;使用PopupWindow组件实现弹出菜单组件开发&#xff1b; 1.2 具体…...

js的继承的方式

1.对象冒充继承 使用 bind,call,apply 解决构造函数属性的继承 缺点:不能继承原型上的属性和方法 //-------------父类-------------function Person(name, age, sex) {this.name name;this.age age;this.sex sex;}Person.prototype.run function () {console.log(我${this…...

聊聊HttpClient的重试机制

序 本文主要研究一下HttpClient的重试机制 HttpRequestRetryHandler org/apache/http/client/HttpRequestRetryHandler.java public interface HttpRequestRetryHandler {/*** Determines if a method should be retried after an IOException* occurs during execution.**…...

北邮22级信通院数电:Verilog-FPGA(4)第三周实验:按键消抖、呼吸灯、流水灯 操作流程注意事项

北邮22信通一枚~ 跟随课程进度更新北邮信通院数字系统设计的笔记、代码和文章 持续关注作者 迎接数电实验学习~ 获取更多文章&#xff0c;请访问专栏&#xff1a; 北邮22级信通院数电实验_青山如墨雨如画的博客-CSDN博客 目录 一.注意事项 二.按键消抖 2.1 LED_deboun…...

Ghidra101再入门(上?)-Ghidra架构介绍

Ghidra101再入门(上&#xff1f;)-Ghidra架构介绍 最近有群友问我&#xff0c;说&#xff1a;“用了很多年的IDA&#xff0c;最近想看看Ghidra&#xff0c;这应该怎么进行入门&#xff1f;“这可难到我了。。 我发现&#xff0c;市面上虽然介绍Ghidra怎么用的文章和书籍很多&…...

Vue3路由引入报错解决:无法找到模块“xxx.vue”的声明文件 xxx隐式拥有 “any“ 类型。

这类情况应该遇见过吧&#xff0c;这是因为 TypeScript只能理解 .ts 文件&#xff0c;无法理解 .vue 文件。 解决方法&#xff1a;在项目的根目录或者src文件夹下创建一个后辍为 文件名.d.ts 的文件&#xff0c;并写入一下内容&#xff1a; declare module *.vue {import { …...

基于若依ruoyi-nbcio支持flowable流程分类里增加流程应用类型

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 主要考虑到流程分很多种&#xff0c;普通的是OA流程&#xff0c;还有自定义业务流程&#xff0c;钉钉流程等…...

JS之同步异步promise、async、await

promise异步操作 Promise是异步编程的一种解决方案 JavaScript异步与同步解析 学习promise前我们先来了解下什么是异步&#xff1f; 基本概念&#xff1a; 消息队列中的任务分为宏任务与微任务;调用栈也可以称为主线程 首先我们要知道js是单线程语言&#xff0c;也就是说…...

【OpenCV • c++】自定义直方图 | 灰度直方图均衡 | 彩色直方图均衡

文章目录 一、什么是直方图二、自定义直方图三、灰度直方图均衡四、彩色直方图均衡一、什么是直方图 直方图广泛应用于很多计算机视觉处理当中。通过标记帧与帧之间显著的边缘和颜色的变化,可以检测视频中的场景变化。在每个兴趣点设置一个有相似特征的直方图所构成的“标签”…...

el-tree目录和el-table实现搜索定位高亮方法

需求&#xff1a;el-tree目录实现搜索查询el-table表格项&#xff0c;双击表格项根据yiZhuMLID||muLuID定位el-tree目录&#xff0c;并且高亮展示在可视化区域内&#xff0c;再重新根据el-tree目录的yiZhuMLID搜索刷新el-table表格&#xff0c;定位且高亮展示相对应的yiZhuMLID…...

linux常用指令

基础命令 cd&#xff1a;用于切换目录。例如&#xff0c;要从当前目录切换到/home/user目录&#xff0c;可以使用命令“cd /home/user”。ls&#xff1a;用于列出目录内容。例如&#xff0c;要列出当前目录的内容&#xff0c;可以使用命令“ls”。mkdir&#xff1a;用于创建目…...

变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析

一、变量声明设计&#xff1a;let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性&#xff0c;这种设计体现了语言的核心哲学。以下是深度解析&#xff1a; 1.1 设计理念剖析 安全优先原则&#xff1a;默认不可变强制开发者明确声明意图 let x 5; …...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!

5月28日&#xff0c;中天合创屋面分布式光伏发电项目顺利并网发电&#xff0c;该项目位于内蒙古自治区鄂尔多斯市乌审旗&#xff0c;项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站&#xff0c;总装机容量为9.96MWp。 项目投运后&#xff0c;每年可节约标煤3670…...

使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装

以下是基于 vant-ui&#xff08;适配 Vue2 版本 &#xff09;实现截图中照片上传预览、删除功能&#xff0c;并封装成可复用组件的完整代码&#xff0c;包含样式和逻辑实现&#xff0c;可直接在 Vue2 项目中使用&#xff1a; 1. 封装的图片上传组件 ImageUploader.vue <te…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

ip子接口配置及删除

配置永久生效的子接口&#xff0c;2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

排序算法总结(C++)

目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指&#xff1a;同样大小的样本 **&#xff08;同样大小的数据&#xff09;**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...

【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)

前言&#xff1a; 双亲委派机制对于面试这块来说非常重要&#xff0c;在实际开发中也是经常遇见需要打破双亲委派的需求&#xff0c;今天我们一起来探索一下什么是双亲委派机制&#xff0c;在此之前我们先介绍一下类的加载器。 目录 ​编辑 前言&#xff1a; 类加载器 1. …...

Chrome 浏览器前端与客户端双向通信实战

Chrome 前端&#xff08;即页面 JS / Web UI&#xff09;与客户端&#xff08;C 后端&#xff09;的交互机制&#xff0c;是 Chromium 架构中非常核心的一环。下面我将按常见场景&#xff0c;从通道、流程、技术栈几个角度做一套完整的分析&#xff0c;特别适合你这种在分析和改…...