【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

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

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

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

相关文章

Qt/C++原创推流工具/支持多种流媒体服务/ZLMediaKit/srs/mediamtx等

一、前言 1.1 功能特点 支持各种本地视频文件和网络视频文件。支持各种网络视频流&#xff0c;网络摄像头&#xff0c;协议包括rtsp、rtmp、http。支持将本地摄像头设备推流&#xff0c;可指定分辨率和帧率等。支持将本地桌面推流&#xff0c;可指定屏幕区域和帧率等。自动启…

【Vuex+ElementUI】Vuex中取值存值以及异步加载的使用

一、导言 1、引言 Vuex是一个用于Vue.js应用程序的状态管理模式和库。它建立在Vue.js的响应式系统之上&#xff0c;提供了一种集中管理应用程序状态的方式。使用Vuex&#xff0c;您可以将应用程序的状态存储在一个单一的位置&#xff08;即“存储”&#xff09;中&#xff0c;…

iPhone15手机拓展坞方案,支持手机快充+传输数据功能

手机拓展坞的组合有何意义&#xff1f;首先是数据存储场景&#xff0c;借助拓展坞扩展出的接口&#xff0c;可以连接U盘、移动硬盘等采用USB接口的设备&#xff0c;实现大文件的快速存储或者流转&#xff1b;其次是图片、视频的读取场景&#xff0c;想要读取相机、无人机SD/TF存…

【angular】实现简单的angular国际化(i18n)

文章目录 目标过程运行参考 目标 实现简单的angular国际化。本博客实现中文版和法语版。 将Hello i18n!变为中文版&#xff1a;你好 i18n!或法语版:Bonjour l’i18n !。 过程 创建一个项目&#xff1a; ng new i18nDemo在集成终端中打开。 添加本地化包&#xff1a; ng a…

042:mapboxGL点击某feature点,使其为中心点

第042个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+mapbox中通过鼠标点击某feature点,让其成为中心点。这里用到了click事件和flyTo的方法。 直接复制下面的 vue+mapbox源代码,操作2分钟即可运行实现效果 文章目录 示例效果配置方式示例源代码(共113行)相关API参…

spring boot+ vue位置信息大数据综合管理平台源码

spring boot vue位置信息大数据综合管理平台源码 UWB技术的人员定位系统源码 智慧工厂是产业升级的外在表现形式&#xff0c;利用物联网技术加强信息管理的新模式&#xff0c;人员定位管理通过物联网技术、位置信息大数据的综合处理应用&#xff0c;在智慧工厂人员管理方面具有…

大模型之Prompt研究和技巧

大模型之Prompt研究和技巧 大模型之Prompt编写简介组成技术Zero-ShotFew-shotCOTCOT-SCTOTGoTReAct 大模型之Prompt编写 简介 Prompt是是给 AI **模型的指令&#xff0c;**一个简短的文本输入&#xff0c;用于引导AI模型生成特定的回答或执行特定任务。 Prompt是你与语言模型沟…

【方法】PDF不能转换成其它格式如何解决?

想把PDF文件转换成其他格式&#xff0c;比如Word、PPT&#xff0c;却发现无法操作&#xff0c;这是什么情况呢&#xff1f;又该如何解决&#xff1f;下面我们一起来看看吧。 原因1&#xff1a;没有使用PDF编辑器 如果是在线打开PDF&#xff0c;或者使用PDF阅读器打开PDF&…

将 mysql 数据迁移到 clickhouse (最新版)

一、前驱知识 已经在mysql中插入了海量的数据了&#xff0c;这个时候mysql 承载不了这么大的数据&#xff0c;并且数据只需要查询&#xff0c;修改和删除非常少&#xff0c;并且不需要支持事务&#xff0c;这个时候需要换一个底层存储&#xff0c;这里选用的是 clickhouse 来进…

【论文阅读】面向抽取和理解基于Transformer的自动作文评分模型的隐式评价标准(实验结果部分)

方法 结果 在这一部分&#xff0c;我们展示对于每个模型比较的聚合的统计分析当涉及到计算特征和独立的特征组&#xff08;表格1&#xff09;&#xff0c;抽取功能组和对齐重要功能组&#xff08;表格2&#xff09;&#xff0c;并且最后&#xff0c;我们提供从模型比较&#x…

解读非托管流动性协议Hover: 差异化、层次化的全新借贷体系

“Hover 是 DeFi 借贷赛道的另辟蹊径者&#xff0c;除了在自身机制&#xff08;借贷模型、治理体系&#xff09;上进行创新获得内生动力外&#xff0c;背靠日渐繁荣的 Kava、Cosmos 生态进一步获得外生动力&#xff0c;发展潜力俱佳” 与 DEX 类似&#xff0c;借贷也是 DeFi 世…

深度学习DAY3:FFNNLM前馈神经网络语言模型

1 神经网络语言模型NNLM的提出 文章&#xff1a;自然语言处理中的语言模型预训练方法&#xff08;ELMo、GPT和BERT&#xff09; https://www.cnblogs.com/robert-dlut/p/9824346.html 语言模型不需要人工标注语料&#xff08;属于自监督模型&#xff09;&#xff0c;所以语言…

React js原生 详解 HTML 拖放 API(鼠标拖放功能)

最近碰到了个需求&#xff0c;大概就是要通过可视化拖拽的方式配置一个冰柜&#xff0c;需要把预设好的冰柜内部架子模板一个个拖到冰箱内。一开始的想法是用鼠标事件&#xff08;mousedown、mouseup等&#xff09;那一套去实现&#xff0c;能实现但是过程过于复杂&#xff0c;…

qt判断当前日期的当月的最后一天是几号

1、拖个dateTimeEdit在界面上&#xff0c;同时来判断输入的时间的最后一天的日期是什么&#xff1f; int year,month;int monthArr[12]{31,28,31,30,31,30,31,31,30,31,30,31};QDateTime time ui->dateTimeEdit->dateTime();year time.toString("yyyy").toIn…

uniapp 显示icon异常

按照文档创建的uni-ui项目&#xff0c;仿照示例程序写的代码中icon显示异常 &#xe470; 异常情况&#xff1a; 正常情况&#xff1a; 通过比对代码发现&#xff0c;示例程序的App.vue中 有一个引用是问题的关键 正是因为多了这一个引用文件&#xff0c;图表的显示才能正常 …

3d tiles规范boundingVolume属性学习

3d tiles的瓦片&#xff08;Tiles&#xff09;包含一些属性&#xff0c;其中第一项是boundingVolume&#xff1b;下面学习boundingVolume&#xff1b; boundingVolume&#xff0c;这个翻译为边界范围框&#xff0c;如果直译为边界体积可能有问题&#xff0c;其实就是包围盒的意…

[Unity][VR]Passthrough2-创建一个基本的Passthrough应用

上一期我们对PassthroughXR项目做好了基本的项目设置,今天我们就开始构建一个基本的Passthrough应用。 我们还是从基本场景开始。先把默认的main camera删除。因为后续我们会引入OVR Rig对象,这个对象自带Camera用来实现VR视角。 在Project面板我们搜索OVR camera rig。看见…

[Mono Depth/3DOD]单目3D检测基础

1.数据增强 图像放缩和裁剪后&#xff0c;相机内参要做相应变化 import random def random_scale(image, calib, scale_range(0.8, 1.2)):scale random.uniform(*scale_range)width, height image.sizeimage image.resize((int(width * scale), int(height * scale)))cali…

10_10C++

X-mid #include <iostream> using namespace std; class Kun {//算术运算符friend const Kun operator(const Kun &k1,const Kun &k2);friend const Kun operator-(const Kun &k1,const Kun &k2);friend const Kun operator*(const Kun &k1,const Ku…

MFC扩展库BCGControlBar Pro v33.6 - 网格、报表控件功能升级

BCGControlBar库拥有500多个经过全面设计、测试和充分记录的MFC扩展类。 我们的组件可以轻松地集成到您的应用程序中&#xff0c;并为您节省数百个开发和调试时间。 BCGControlBar专业版 v33.6已正式发布了&#xff0c;此版本包含了对图表组件的改进、带隐藏标签的单类功能区栏…