RabbitMQ的基本架构与实现原理

article/2025/10/22 4:52:04

目录

1.RabbitMQ Exchange类型

2.RabbitMQ的数据存储


RabbitMQ整体逻辑架构

 1.RabbitMQ Exchange类型

常用的交换器类型分为:Direct、Topic、 Fanout、Header 四种。

Fanout

fanout类型的交换器会把所有发送到该交换器的消息路由到所有与该交换器绑定的队列中,如图:

 Direct

direct类型的交换器会把发送到该交换器的消息路由到BindingKey 与 RoutingKey完全匹配的队列中,如图:

 Topic

topic类型的交换器在direct的匹配规则上进行了拓展,也是将消息路由到BindingKey 和 RoutingKey相匹配的队列中,但是匹配规则有些不同:

        BindingKey 和 RoutingKey都是由 "." 分隔的字符串,BindingKey中存在两种特殊字符" # "和" * ",用户模糊匹配,其中" * "用于匹配一个单词,” # “用于匹配多个单词。

 Headers

headers类型的交换器不依赖于路由键的匹配规则来路由信息,而是根据发送的消息内容中的headers属性进行匹配。在绑定队列和交换器时指定一组键值对,当发送的消息到交换器时,RabbitMQ会获取到该消息的headers, 对比其中的键值对是否完全匹配队列和交换器绑定时指定的键值对,如果匹配,消息就会路由到该队列。headers类型的交换器性能很差,不实用。

2.RabbitMQ的数据存储

        存储机制

        RabbitMQ的消息分为两种类型:持久化消息和非持久化消息。

        这两种消息都会被写入磁盘

        持久化消息在到达队列时写入磁盘,同事内存中会保存一份备份,当内存吃紧时,消息从内存中剔除,会提高一定的性能。

        非持久化消息一般只存在与内存中,当内存压力大时数据刷盘处理,以节省内存空间。

        

RabbitMQ存储层包含两个部分:

        队列索引(rabbit_queue_index)和消息存储(rabbit_msg_store)

        队列索引:rabbit_queue_index

        索引维护队列的落盘消息的信息,如存储地点,是否已经被消费者接收,是否已经被消费者ack等,每个队列都有对应的索引。

 索引使用顺序的段文件来存储,后缀为.idx, 文件名从0开始累加,每个段文件中包含固定的segment_entry_count条记录,默认值是16384。每个index从磁盘中读取信息的时候,至少要在内存中维护一个段文件,所以设置 queue_index_embed_msgs_below 值的时候要格外谨慎,一点点增大也可能导致内存爆炸式增长。

         消息存储:rabbit_msg_store

        消息以键值对的形式存储到文件中,一个虚拟主机上的所有队列共用一块存储,每个节点只有一个。存储分为持久化存储(msg_store_persistent) 和短暂存储(msg_store_transient)。持久化存储的内容在broker重启后不会丢失,短暂存储的内容在broker重启后会丢失。

        store 使用文件来存储,后缀.rdq,经过store处理过的所有消息都会以追加的方式写入到该文件中,当文件大小超过指定限制(file_size_limit)后,将会关闭该文件并创建一个新文件以供新消息写入。文件名从0开始进行累加。在进行消息存储时,RabbitMQ会在ETS(Erlang Term Storage)表中记录消息在文件中的位置映射和文件的相关信息

        在进行消息存储时,RabbitMQ会在ETS表中记录消息在文件中的位置映射和文件的相关信息。

        消息(包括消息头,消息体,属性)可以直接存储在index中,也可以存储在store中。最佳方式是较小的消息存储在index中,较大的消息存储在store中。 消息大小的界定可以通过queue_index_embed_msgs_below来配置,默认是4096B。当一个完整消息小于设定的大小阈值时,就可以存储在index中,这样性能上可以得到优化(这也是修改消息大小界定可能导致内存爆炸式增长的原因)。

msg 的大小 > queue_index_embed_msgs_below ?

                        存储到 msg_store_persistent的 <num>.rdq文件中 :

                        存储到<num>.idx索引文件中

        读取文件时,先根据消息的ID(msg_id)找到对应的文件,如果文件存在并且未被锁住,则直接打开文件,从指定位置读取消息内容,如果文件不存在或被锁住了,则发送请求由store进行处理。

        删除消息时,只是从ETS表删除指定消息的相关信息,同时更新消息对应的存储文件和相关信息。在执行消息删除操作时,不立即对文件进行删除,消息仍存在文件中,但是会被标记为垃圾数据。当一个文件中的所有消息都是垃圾数据时可以将这个文件删除。 当检测到前后两个文件中的有效数据可以合并成一个文件,并且所有的垃圾数据的大小和所有文件的数量(至少3个文件存在的情况下)大小的比值超过设置的阈值 garbage_fraction(默认0.5)时,才会触发垃圾回收,将这两个文件合并,执行合并的文件一定是逻辑上相连的两个文件,合并逻辑:

        1:先锁定两个文件

        2:先整理前面文件的有效数据,再整理后面的文件的有效数据

        3:将后面的文件的有效数据全部写入到前面的文件中

        4:更新消息再ETS表中的记录

        5:删除后面的文件

        队列结构

        通常队列 由 rabbit_amqqueue_process 和 backing_queue 这两部分组成。

rabbit_amqqueue_process 负责协议相关的消息处理,即接收生产者发布的消息,向消费者交付消息,处理消息的确认(包括生产端的confirm 和 消费端的 ack)等。 backing_queue 是消息存储的具体形式和引擎,并向 rabbit_amqqueue_process 提供相关的接口以供调用。

如果消息投递的目的队列当前为空,且有消费者订阅该队列,则该消息直接发送给消费者,不经过队列这一步。当消息无法直接投递给消费者时,需要将消息暂存入队列,以便重新投递。

        rabbit_variable_queue.erl源码中定义了RabbitMQ队列的4种状态:

                1.alpha: 消息索引和消息内容都存内存,最耗内存,很少消耗CPU

                2.beta: 消息索引存内存,消息内容存磁盘

                3.gama:消息索引内存和磁盘都有,消息内容存磁盘

                4. delta:消息索引和内容都存磁盘,基本不消耗内存,消耗更多CPU和I/O操作

        消息存如队列后,不是固定不变的,会随着系统的负载在队列中不断流动,消息的状态会不断发生变化。

        gama状态只有持久化消息才会有的状态。

        在运行时,RabbitMQ会根据消息传递的速度定期计算一个内存中能保存的最大消息数量(target_ram_count), 如果alpha状态的消息大于此值,则会引起消息状态的转换,多余的消息可能会转换到beta、gama或者delta状态。区分这四种状态的主要作用是满足不同的内存和CPU需求

        对于普通没有设置优先级和镜像的队列来说,backing_queue的默认实现是 rabbit_variable_queue,其内部通过 5 个 子队列Q1, Q2,delta、Q3、Q4体现消息的各个状态。

消费者获取消息也会引起消息的状态转换。

当消费者获取消息时

        1.首先会从Q4中获取消息,如果获取成功则返回。

        2.如果Q4为空,则尝试从Q3中获取,系统首先会判断Q3是否为空,如果为空则返回队里欸为空,即此时队列中无消息。

        3.如果Q3不为空,则取出Q3中的消息,再判断此时Q3和Delta中的长度,如果都为空,则可以认为Q2、Delta、Q3、Q4全部为空,此时将Q1中的消息直接转移至Q4,下次直接从Q4中获取消息。

        4.如果Q3为空,Delta不为空,则将Delta的消息转移至Q3中,下次可以直接从Q3中获取消息。在将消息从Delta转移到Q3的过程中,是按照索引分段读取的,首先读取某一段,然后判断读取的消息个数与Delta中的消息个数是否相等,如果相等,则判断Delta中已无消息,则直接将Q2和刚读取到的消息放入到Q3中,如果不相等, 仅将此次读取的消息转移到Q3。

这里有两处疑问:

        1.为什么Q3为空则可以认定整个队列为空?

        试想,如果Q3为空,Delta不为空,那个Q3取出最后一条消息的时候,Delta上的消息就会被转移到Q3这样与Q3为空矛盾;

        如果Delta为空且Q2不为空,则在Q3取出最后一条消息时会将Q2的消息并入到Q3中,这样也与Q3为空矛盾;

        在Q3被取出最后一条消息之后,如果Q2、Delta、Q3为空,且Q1不为空时,Q1的消息会直接转移到Q4,这与Q4为空矛盾。

以上的论证也解释了另一个问题:为什么Q3和Delta都为空时,则可以认为整个队列为空?

         通常在负载正常时,如果消费速度远大于生产速度,对于不需要保证可靠不丢失的消息来说,极有可能只会处于alpha状态。

        对于持久化消息,它一定会进入到gamma状态,在开启publisher confirm 机制时,只有到了 gamma 状态时,才会确认该消息已被接收,若消息消费速度足够快,内存也充足,这些消息也不会走到下一个状态。

        消息堆积导致性能下降的原因:

        在系统负载较高时,消息若不能很快被消费掉,则会进入到很深的队列中,这样会增加处理每个消息的平均开销。因为需要花更多的时间和资源处理堆积的消息,处理新消息的能力便会降低,使得后流入的消息进入到更深的队列中,恶性循环 使得系统处理能力大大降低。

        应对这种问题一般有三种措施:

                1.增加prefetch_count的值,即一次发送多条消息给消费者,加快消息被消费的速度。

                2.采用multiple ack, 降低处理 ack 带来的开销。

                3.流量控制。


http://chatgpt.dhexx.cn/article/Kp5eqJas.shtml

相关文章

Rabbit Mq 底层原理

为什么要用MQ&#xff1f;MQ有什么好处&#xff1f; 1、异步通信&#xff1a;通过异步通信&#xff0c;可以减少客户端等待时间&#xff0c;实现接口快速响应 2、系统解耦&#xff1a;对于复杂的系统&#xff0c;减小系统与系统之间的依赖 3、流量削峰&#xff1a;对于瞬时访问…

RabbitMQ工作原理以及常见面试题【2022版】

RabbitMQ工作原理图&#xff1a; Broker&#xff1a;接收和分发消息的应用&#xff0c;RabbitMQ Server 就是 Message Broker Virtual host&#xff1a;出于多租户和安全因素设计的&#xff0c;把 AMQP 的基本组件划分到一个虚拟的分组中&#xff0c;类似 于网络中的 namespac…

RabbitMQ原理简单介绍

其实这篇博客&#xff0c;也算不上是什么原理&#xff0c;只是将我知道的一些RabbitMQ的知识简单罗列下&#xff0c;自从我来公司到现在&#xff0c;虽然一直都在用RabbitMQ&#xff0c;也一直想着把这块总结下&#xff0c;却一直在给自己找借口&#xff0c;最近一段时间&#…

MQ - RabbitMQ - 架构及工作原理

参考网址&#xff1a; RabbitMQ的应用场景以及基本原理介绍 RabbitMQ使用详解 RabbitMQ的Java应用(1) -- Rabbit Java Client使用 1. 系统架构 几个概念说明: Broker:它提供一种传输服务,它的角色就是维护一条从生产者到消费者的路线&#xff0c;保证数据能按照指定的方式进…

RabbitMQ 详解

RabbitMQ 详解 MQ 的相关概念RabbitMQ 四大核心概念RabbitMQ 的工作原理RabbitMQ 六大核心部分&#xff08;模式&#xff09;简单模式工作模式工作模式案例消息确认&#xff08;消息应答&#xff09;消息持久化 发布确认模式交换机&#xff08;Exchange&#xff09;Exchange 概…

RabbitMq原理及应用

一、简介 MQ(Message Queue),即消息队列&#xff0c;是一种实现应用级别之间的通信手段。不同应用之间可以通过读写消息&#xff0c;以消息为媒介传递应用数据&#xff0c;不需要应用之间建立强连接。此方式与远程调用&#xff08;RPC&#xff09;是应用通信的常见方式。在这个…

RabbitMQ原理解析

场景模拟 在介绍RabbitMQ之前&#xff0c;我们先来看下面一个电商项目的场景&#xff1a; 商品的原始数据保存在数据库中&#xff0c;增删改查都在数据库中完成。搜索服务数据来源是索引库&#xff08;Elasticsearch&#xff09;&#xff0c;如果数据库商品发生变化&#xff0…

Rabbitmq基本原理和架构

全栈工程师开发手册 &#xff08;作者&#xff1a;栾鹏&#xff09; 架构系列文章 rabbitmq官网:https://www.rabbitmq.com/rabbitmqctl.8.html MQ全称为Message Queue, 是一种分布式应用程序的的通信方法&#xff0c;它是消费-生产者模型的一个典型的代表&#xff0c;produc…

RabbitMQ — RabbitMQ使用以及原理解析

RabbitMQ使用以及原理解析 RabbitMQ是一个由erlang开发的AMQP(Advanved Message Queue)的开源实现;在RabbitMQ官网上主要有这样的模块信息, Work queues消息队列,Publish/Subscribe发布订阅服务,Routing, Topics, RPC等主要应用的模块功能. 几个概念说明: Broker:它提供一种传…

RabbitMQ介绍及工作原理

RabbitMQ介绍及工作原理 一&#xff0c;什么是RabbitMQ ​ RabbitMQ是一种称为消息代理或队列管理器的消息队列软件。它是一个可以定义队列的软件&#xff0c;应用程序可以连接到队列并将消息传输到它们。消息队列的基本体系结构很简单&#xff1a;存在称为生产者的客户端应用…

彻底理解RabbitMQ底层原理

1.RabbitMQ概念 RabbitMQ 是一个由 Erlang 语言开发的 AMQP 的开源实现。 AMQP &#xff1a;Advanced Message Queue&#xff0c;高级消息队列协议。它是应用层协议的一个开放标准 &#xff0c;为 面向消息的中间件设计&#xff0c;基于此协议的客户端与消息中间件可传递消息&…

rabbitmq消息队列原理

一、rabbitmq架构 RabbitMQ是一个流行的开源消息队列系统&#xff0c;是AMQP&#xff08;高级消息队列协议&#xff09;标准的实现&#xff0c;由以高性能、健壮、可伸缩性出名的Erlang语言开发&#xff0c;并继承了这些优点。rabbitmq简单架构如下&#xff1a; 上图简单展…

SpringBoot整合RabbitMQ及其原理分析

上一篇&#xff1a;RabbitMQ基础知识 1、相关依赖 这里无需指定版本号&#xff0c;让其跟着SpringBoot版本走。本示例使用SpringBoot版本号为2.7.10。 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-…

rabbitmq详解

rabbitmq 一、简介二、业务场景1、异步2、应用解耦3、流量削峰 三、下载四、界面认识五、五种模型示例0、springboot依赖配置1、Hello World简单模型2、Work queues工作队列3、Publish/Subscribe发布订阅模型4、Routing路由模型5、Topics主题模型6、消息转换器 六、进阶1、消费…

[RabbitMQ--1] MQ简介

目录 1.MQ 的相关概念 1.1.什么是 MQ&#xff1f; 1.2.为什么要用MQ&#xff1f;MQ的应用场景 1.2.1.流量消峰&#xff1a; 1.2.2.任务异步处理&#xff1a; 1.2.3.应用解耦 2.AMQP和JMS 3.MQ 的分类 1.ActiveMQ 2.Kafka 3..RocketMQ 4..RabbitMQ 4.RabbitMQ 1.四…

什么是RabbitMq?其原理?

什么是RabbitMq&#xff1f; RabbitMQ是一个实现了AMQP&#xff08;Advanced Message Queuing Protocol&#xff09;高级消息队列协议的消息队列服务&#xff0c;用Erlang语言。 rabbitmq原理 1.Producer&#xff1a;即数据的发送方。创建消息并将其发布(发送)到代理服务器 一…

RabbitMQ原理详解

RabbitMQ&#xff1a;我们通常谈到消息队列&#xff0c;就会联想到这其中的三者&#xff1a;生产者、消费者和消息队列&#xff0c;生产者将消息发送到消息队列&#xff0c;消费者从消息队列中获取消息进行处理。对于RabbitMQ&#xff0c;它在此基础上做了一层抽象&#xff0c;…

你应该知道的 9 种 前端设计模式

本篇文章给大家介绍 9 种 前端设计模式。有一定的参考价值&#xff0c;有需要的朋友可以参考一下&#xff0c;希望对大家有所帮助。 什么是设计模式&#xff1f; 设计模式是对软件设计开发过程中反复出现的某类问题的通用解决方案。设计模式更多的是指导思想和方法论&#xff…

前端需要了解的设计模式

什么是设计模式&#xff1f; 设计模式是对软件设计开发过程中反复出现的某类问题的通用解决方案。设计模式更多的是指导思想和方法论&#xff0c;而不是现成的代码&#xff0c;当然每种设计模式都有每种语言中的具体实现方式。学习设计模式更多的是理解各种模式的内在思想和解…

前端设计模式应用

前端设计模式应用 什么是设计模式 软件设计中常见问题的解决方案模型: 历史经验的总结与特定语言无关 设计模式背景 模式语言:城镇、建筑、建造 (A Pattern Language:Towns, Buildings,Construction)1977设计模式:可复用面向对象软件的基础 (Design Patterns: Elements of …