RabbitMQ 详解(核心概念)
本文是博主在梳理 RabbitMQ 知识的过程中,将所遇到和可能会遇到的基础知识记录下来,用作梳理 RabbitMQ 的整体架构和功能的线索文章,通过查找对应的知识能够快速的了解对应的知识而解决相应的问题。
文章目录
- 一、RabbitMQ 是什么?
- 二、RabbitMQ 的核心概念
- 01、消息(Message)
- 02、生产者(Producer)
- 03、消费者(Consumer)
- 04、消息中间件的服务节点(Broker)
- 05、队列(Queue)
- 06、交换机(Exchange)
- 07、路由键(RoutingKey)
- 08、绑定(Binding)
- 09、信道(Channel)
- 10、连接(Connection)
- 11、虚拟主机(Virtual Host, vHost)
- 10、多租户(Multi-Tenancy)
- 11、虚拟主机与多租户的对比与延伸
- 三、协议与通信
- 1. AMQP 协议(Advanced Message Queuing Protocol)
- 2. MQTT 协议(Message Queuing Telemetry Transport)
- 3. STOMP 协议(Simple Text Oriented Messaging Protocol)
一、RabbitMQ 是什么?
RabbitMQ 是一个开源的消息中间件(Message Broker),基于 AMQP
(高级消息队列协议,Advanced Message Queuing Protocol)实现,旨在为分布式系统提供可靠的异步通信解决方案。
在开发中引入 RabbitMQ 中间件一般用作不同项目之间的消息传递。例如在即时通讯项目中,常会将不同的业务进行构建独自的服务项目,比如消息服务、文件服务、状态服务和查询服务等,各个服务之间相互独立又彼此相连。例如用户状态(上线或下线)的传递,实时传输到各个服务,而又不会受到其他服务的影响,实现解耦。
- 异步通信桥梁:允许不同应用程序通过
消息
进行间接通信,无需实时同步响应,提升系统解耦性和可扩展性。
使用 RabbitMQ 还有一个好处就是他的消息传递是通过交换机传输到队列中,消息队列具有一定的容量可以应对流量的波动。例如一个大型的即时通讯服务,用户的状态会经常发生变化(上线-离开-在线-请勿打扰)等等,例如早晨用户状态变化可能会急剧增加,用户在进入离开状态会有一段时间,就会出现一个状态变化的峰值。消息队列能够存储一定的流量,缓解消费者的压力,同时稳定服务的消费能力不会大幅变化。
- 削峰填谷:通过消息队列暂存峰值流量,缓解后端服务压力,适用于流量波动较大的场景(如电商促销、日志处理)。
状态服务的消息传输是需要稳定传输的,不然你就可能会和一个 下线
的人在聊天,这就会影响用户体验,基于此,RabbitMQ 具有机制保障消息能够可靠的传输。
- 可靠消息传递:支持消息持久化、确认机制(ACK)、重试策略等,确保消息不丢失或重复处理。
此外 RabbitMQ 还具有一些其他优势,如:
- 多语言支持:提供 Java、Python、C#、Go、JavaScript 等主流语言的客户端库,方便跨平台集成。
- 高可用性与集群:支持节点集群部署(如镜像队列),实现故障转移和负载均衡,保障服务稳定性。
- 插件生态:通过插件扩展功能,例如管理界面(RabbitMQ Management Plugin)、STOMP/MQTT 协议支持、消息追踪等。
- 轻量与高效:基于 Erlang 语言开发,天生支持高并发和低延迟,适合分布式系统环境。与 Kafka 等吞吐量优先的中间件相比,RabbitMQ 在处理超大规模数据时性能稍弱,更适合中等规模、注重可靠性的业务。
RabbitMQ 是分布式系统中实现异步通信的核心工具,通过消息队列、交换机和路由规则的组合,帮助开发者解耦系统模块、提升容错能力,适用于需要可靠消息传递的企业级应用,如金融、电商、物流等领域。
二、RabbitMQ 的核心概念
RabbitMQ 整体上是一个生产者和消费者模型,主要负责接收,存储和转发消息。
上图是从网上找的网图,标有作者,如有侵权请联系删除。
我们可以从该图了解里面的工作流程:生产者生产消息,携带路由键发布到交换器中,交换器根据绑定键路由到不同的队列,消费者根据所订阅的队列消费消息。
01、消息(Message)
通信的最小单元,通常包含两个部分:消息体和标签。
- 消息体:消息体也可以称之为内容(Payload),实际数据(如 JSON 格式的订单信息)。
- 标签:有时被称为
元数据
,用来表述这条消息。- 例如:路由键、过期时间、优先级、是否持久化等。
- 如物流消息:标注
易碎品
(属性),通知消费者轻拿轻放。
类比:快递包裹,内部是商品(Payload),外部面单是元数据(地址、重量、保价等)。
02、生产者(Producer)
投递消息的一方,常见于发送消息的应用程序或服务。
- 不关心消息如何被处理,只负责将消息丢给 RabbitMQ。
- 如打车软件:司机接单后,将行程信息发送到消息队列,由后台系统异步派单。
- 支持批量发送、消息持久化等配置。
类比:餐厅厨师,做好餐后将菜品(消息)交给传菜员(RabbitMQ),不关心顾客何时就餐。
03、消费者(Consumer)
接收并处理消息的应用程序或服务。当消费者消费一条消息时,只是消费消息的消息体(payload)。在消息路由的过程中,消息的标签会被丢弃,存入到队列的只有消息体,消费者也只会消费到消息体,也就不知道消息的生产者是谁。
- 主动
订阅
队列,按需拉取消息。- 如电商订单系统:库存服务监听
扣库存
队列,收到消息后执行扣减操作。
- 如电商订单系统:库存服务监听
- 支持消息确认(ACK):处理完成后通知 RabbitMQ 移除消息,避免丢失。
类比:超市收银员,从传送带(队列)上取商品(消息)扫码结账,完成后商品离开传送带。
04、消息中间件的服务节点(Broker)
在学习 RabbitMQ 时,经常会遇到这个这个概念,英文直译为中间件(经纪人),一般是消息队列的服务实体。
对于 RabbitMQ 来说,一个 RabbitMQ Broker 可以简单的看作一个 RabbitMQ 服务节点,或者 RabbitMQ 服务实例,大多数情况下也可以看作一台 RabbitMQ 服务器。
05、队列(Queue)
RabbitMQ 的内部对象,消息的最终存储容器,消费者从这里获取消息,可以理解成存放消息的 临时仓库
,支持 异步收发
和 削峰填谷
。RabbitMQ 的消息只能存储在队列里,和 Kafka 正好相反,Kafka 将消息存储在 topic (主题)这个层面,而相应的队列逻辑只是 topic 实际存储文件中的位移标识。RabbitMQ 最终生产的消息最终会投递到队列中,供消费者消费。
- 支持持久化(消息存磁盘,RabbitMQ 重启不丢失)。
- 多消费者竞争消费(如订单队列:多个支付服务节点同时处理订单,提升吞吐量)。
当多个消费者可以订阅同一个队列,这时消息默认会平均分摊(Round-Ronbin,轮询)给多个消费者进行处理。
- 解耦生产者和消费者(如外卖平台:商家出餐后将“餐品”放入取餐柜,骑手按需取餐,无需实时等待)。
- 应对流量波动(如电商大促:订单消息先存入队列,避免瞬间压垮支付系统)。
06、交换机(Exchange)
RabbitMQ 最终生产的消息最终会投递到队列中,供消费者消费。在这个过程中,消息是先发送到 Exchange 交换器,由交换器将消息根据 路由规则
路由到一个或者多个队列中。如果路由不到,或许会返还给生产者,也有可能会丢弃消息。
交换器只负责转发消息,不具备存储功能,可以理解成一个简单的实体。交换器有四种不同的类型,不同的类型有不同的类型策略,会在第四章详细介绍。
- Direct(精准匹配):消息携带
路由键
,交换机按键
路由到对应队列。 - Fanout(广播):消息直接复制到所有绑定队列。
- Topic(模式匹配):支持通配符(如“user.#”匹配“user.register”“user.login”等队列)。
- headers (头交换机):不依赖路由键的匹配功能,而是根据发送消息中的 headers 属性进行匹配。
07、路由键(RoutingKey)
生产者将消息发送给交换机的时候,一般会指定一个 RoutingKey,用来指定这个消息的路由规则,而这个 RoutingKey 需要与交换器类型和绑定键 BindingKey
联合使用才会生效。
08、绑定(Binding)
RabbitMQ 通过绑定将交换器和队列关联起来,在绑定的时候一般会指定一个绑定键 BindiingKey
,这样就知道如何正确的将不同的消息路由到正确的队列。
整体来说:生产者将消息发给交换器时,需要一个 RoutingKey
,当 BindingKey
和 RoutingKey
相匹配时,消息会被路由到对应队列中。在绑定多个队列到一个交换器时,这些绑定允许使用相同的 BindingKey 。
BindingKey 并不是在所有的情况下都生效,它依赖于交换器类型,例如在 fanout 和 header 交换器中就会失效。
- 交换器相当于投递包裹的邮箱。
- RoutingKey 相当于填写在包裹上的地址。
- BindingKey 相当于包裹的目的地。
- 在使用绑定的时候,需要的路由键是 BindingKey。
- 在发送消息的时候,需要的路由键是 RoutingKey。
- 一个交换机可绑定多个队列,一个队列可绑定多个交换机。
09、信道(Channel)
生产者和消费者与 RabbitMQ 通信的轻量级通道,复用 TCP 连接。
- 避免频繁创建 TCP 连接(一个连接可创建多个信道,如 1 个连接支持 1000 个信道,节省资源)。
- 线程安全:每个线程独立使用信道,互不干扰(如电商订单服务:10 个线程通过 1 个连接的 10 个信道并发发送消息)。
类比:高速公路的“车道”,多个车辆(消息)通过同一条高速(连接)的不同车道(信道)并行行驶。
10、连接(Connection)
生产者和消费者与 RabbitMQ 建立的TCP 长连接。 其核心生命周期:
- 建立:耗时操作(需认证、协商参数),建议复用。
- 心跳机制:防止连接中断(默认 60 秒发送一次心跳包)。
- 关闭:异常时自动重连(如网络闪断后,消费者重新建立连接继续消费)。
类比:打电话时的“通话链路”,一次拨号(连接)支持多次对话(信道传输消息),挂断后需重新拨号。
11、虚拟主机(Virtual Host, vHost)
虚拟主机是 RabbitMQ 中一种 逻辑隔离机制,类似于操作系统中的
目录
或数据库中的Schema
,相当于逻辑隔离的容器
。
它将单个 RabbitMQ 服务器划分为多个独立的环境,每个环境拥有自己的 Exchange(交换器)
、Queue(队列)
、Binding(绑定)
、用户权限
等资源,且这些资源在不同虚拟主机之间完全隔离(除非显式共享,通常不会)。
- 资源隔离:每个虚拟主机是一个独立的沙箱,例如租户 A 的队列
order_queue
和租户 B 的队列order_queue
互不干扰,因为它们属于不同虚拟主机。 - 权限控制单元:虚拟主机是 RabbitMQ 权限管理的最小粒度。管理员可为每个虚拟主机单独配置用户的 读/写/配置权限,例如用户
user1
只能访问虚拟主机vhost1
中的队列,无法查看vhost2
的内容。 - 配置独立:每个虚拟主机可自定义连接地址(如
amqp://user:password@host:port/vhost1
),甚至支持不同的插件配置(尽管较少使用)。 - 多租户支持:一个 RabbitMQ 实例可创建多个
vHost
,供不同业务线使用。 - 与物理服务器的关系:虚拟主机是逻辑隔离,而非物理隔离。多个虚拟主机共享 RabbitMQ 服务器的内存、CPU 等资源,但通过权限和命名空间隔离避免数据交叉。
- 与连接(Connection)的关系:客户端连接时需指定虚拟主机(默认是
/
),一个连接只能属于一个虚拟主机,无法跨虚拟主机操作资源。 - 与消息路由的关系:Exchange、Queue 的名称在虚拟主机内唯一,跨虚拟主机可重复,路由规则仅在当前虚拟主机内生效。
10、多租户(Multi-Tenancy)
多租户指一个软件系统为 多个独立租户(如企业、团队、应用) 提供服务,且确保租户之间的数据、配置、资源相互隔离,同时共享底层基础设施(降低成本),属于系统级隔离架构。
核心目标是:
- 隔离性:租户 A 的数据不能被租户 B 访问,故障不扩散。
- 可配置性:每个租户可自定义参数(如队列优先级、消息保留策略)。
- 资源效率:共享服务器资源,通过配额管理避免单个租户耗尽资源。
RabbitMQ 的虚拟主机是实现多租户的核心机制,二者关系如下:
- 虚拟主机是多租户的“载体”:每个租户分配一个独立虚拟主机,租户的所有消息实体(队列、交换器等)均在其中创建,从命名空间和权限上实现隔离。
- 结合权限系统强化隔离:通过
user_tags
(如administrator
、management
)和permission
(配置、读、写权限),可精确控制租户对虚拟主机的操作范围。例如,租户 A 的用户只能 读 自己虚拟主机的队列,不能删除交换器。 - 资源配额补充隔离:虽然虚拟主机本身不提供严格的资源限制(如内存、带宽配额),但可通过 RabbitMQ 的 资源限制插件(如
rabbitmq_shovel
或外部工具) 为不同租户分配资源上限,避免资源抢占。
与微服务、云架构的结合:
- 微服务多租户:若微服务架构中不同业务线(如电商的
用户服务
和订单服务
)需隔离,可将每个服务分配到独立虚拟主机,避免队列名称冲突或权限泄漏。 - SaaS 应用场景:云服务商为每个客户(租户)创建专属虚拟主机,客户的消息管道完全独立,同时共享同一套 RabbitMQ 集群,降低基础设施成本。
- 多环境隔离:开发、测试、生产环境可使用不同虚拟主机,避免误操作影响线上环境(如误删生产队列)。
11、虚拟主机与多租户的对比与延伸
维度 | 虚拟主机(技术实现) | 多租户(架构目标) |
---|---|---|
定位 | RabbitMQ 内置的逻辑隔离机制,偏技术细节。 | 系统设计目标,关注租户间的隔离、共享与资源管理。 |
核心价值 | 命名空间隔离、权限控制、连接独立。 | 支持多租户的商业模型(如 SaaS),平衡隔离与效率。 |
依赖关系 | 多租户可通过虚拟主机实现,但还需结合权限、配额等。 | 虚拟主机是多租户的一种实现方式,非唯一(如通过独立集群实现)。 |
与其他中间件的对比
- Kafka 的多租户:通过 Topic(主题)+ ACL(访问控制列表) 实现,租户共享集群,但通过 Topic 隔离数据,权限控制更细粒度(如按 Topic 授权),但缺乏类似虚拟主机的“整体隔离容器”。
- RocketMQ 的多租户:通过 Namespace(命名空间) 实现,与 RabbitMQ 虚拟主机类似,每个 Namespace 包含独立的 Topic、Group 等资源,支持租户级隔离。
实践中的注意事项
- 资源分配均衡:虚拟主机不提供物理隔离,需通过集群节点部署、流量控制等避免单个租户拖垮整体性能。
- 权限最小化原则:为每个租户的用户账户分配最小必要权限(如仅
读
或写
队列),防止越权操作。 - 监控与日志分离:通过 RabbitMQ 管理界面或插件(如
rabbitmq_prometheus
)按虚拟主机监控指标(如队列长度、消息吞吐量),便于租户级故障排查。 - 跨租户通信:若需租户间消息共享,可通过
跨虚拟主机转发
(如使用 Shovel 插件将消息从一个虚拟主机复制到另一个),但需谨慎设计,避免破坏隔离性。
RabbitMQ 的虚拟主机是实现多租户的核心技术手段,通过逻辑隔离和权限控制,为多个租户提供独立的消息通信空间。二者结合后,既能满足企业内部多团队协作的隔离需求,也能支撑云原生时代 SaaS 应用的商业化架构。
理解这两个概念的关键在于把握 隔离与共享的平衡 ——虚拟主机在技术层面提供容器化隔离,多租户则从架构层面定义了如何利用这种隔离实现高效的资源分配与安全保障。
架构全景图(结合概念)
生产者 → 连接 → 信道 → 交换机(根据Binding路由)→ 队列 → 信道 → 消费者 └── 虚拟主机(隔离环境) ── 消息(含元数据)
总结:RabbitMQ 通过这些组件的协作,实现了 生产者无需知道消费者是谁、消费者无需实时等待生产者 的异步通信,是分布式系统解耦的基石。
三、协议与通信
1. AMQP 协议(Advanced Message Queuing Protocol)
AMQP 是一种开放标准的应用层协议,专为面向消息的中间件设计,支持跨平台、跨语言的企业级消息通信。其核心目标是提供可靠、灵活的消息传递机制,适用于复杂的分布式系统。
核心特点:
- 可靠传输:支持消息确认(ACK/NACK)、持久化存储、事务机制,确保消息不丢失。
- 灵活路由:通过交换器(Exchange)、**队列(Queue)和绑定(Binding)**实现动态消息路由。交换器类型包括:
- 直连(Direct):基于精确的路由键匹配。
- 主题(Topic):支持通配符模式匹配路由键。
- 扇出(Fanout):广播到所有绑定队列。
- 头部(Headers):基于消息属性而非路由键。
- 多语言支持:兼容多种编程语言(如Java、Python、C#)。
- 协议版本:
- AMQP 0-9-1:广泛实现(如RabbitMQ),采用传统的交换器-队列模型。
- AMQP 1.0:标准化协议,简化模型,更注重通用消息传递(如Apache ActiveMQ支持)。
适用场景:
- 企业应用集成(如银行交易、订单处理)。
- 云计算服务(如Azure Service Bus、RabbitMQ)。
- 需要复杂路由和高可靠性的系统。
2. MQTT 协议(Message Queuing Telemetry Transport)
MQTT 是一种轻量级的发布/订阅模型协议,专为低带宽、高延迟或不稳定网络环境设计,广泛应用于物联网(IoT)场景。
核心特点:
- 极简设计:协议头部仅2字节,减少传输开销。
- QoS分级:
- QoS 0(最多一次):尽力交付,无重传。
- QoS 1(至少一次):确保消息到达,但可能重复。
- QoS 2(恰好一次):通过四次握手保证精确一次交付。
- 主题层级:支持通配符(
+
单层、#
多层)订阅,如sensors/+/temperature
。 - 遗嘱消息(Last Will):客户端异常断开时,代理自动发布预设消息。
- 协议版本:
- MQTT 3.1.1:主流版本,广泛支持。
- MQTT 5.0:增强功能(如原因码、共享订阅、流量控制)。
适用场景:
- 物联网设备通信(如传感器数据上报、智能家居控制)。
- 移动应用推送(弱网环境)。
- 需要低功耗和高效传输的嵌入式系统。
实现依赖:
在RabbitMQ等中间件中需启用插件(如 rabbitmq_mqtt
)支持。
3. STOMP 协议(Simple Text Oriented Messaging Protocol)
STOMP 是一种基于文本的简单协议,设计目标是实现客户端与消息代理之间的跨语言互操作性,通常结合WebSocket用于浏览器通信。
核心特点:
- 文本帧结构:类似HTTP,命令与标头为纯文本,消息体可包含任意格式(如JSON、XML)。
- 示例帧:
SEND destination:/queue/test content-type:text/plainHello, STOMP!
- 示例帧:
- 基础命令:
CONNECT
/STOMP
:建立连接。SEND
:发送消息到目标(队列或主题)。SUBSCRIBE
:订阅目标。ACK
/NACK
:消息确认。
- 简单性:无内置路由机制,依赖代理的队列/主题管理。
- 跨平台性:易于通过Telnet或浏览器(WebSocket)调试。
适用场景:
- 浏览器实时通信(如股票行情推送、聊天应用)。
- 需要快速原型开发或简单消息交互的系统。
- 与其他文本协议(如HTTP)集成的场景。
实现依赖:
在RabbitMQ等中间件中需启用插件(如 rabbitmq_stomp
)支持。
协议对比
特性 | AMQP | MQTT | STOMP |
---|---|---|---|
设计目标 | 企业级可靠消息传递 | 轻量级物联网通信 | 简单文本交互 |
协议类型 | 二进制 | 二进制 | 文本 |
路由灵活性 | 高(多类型交换器) | 中(基于主题层级) | 低(依赖代理实现) |
QoS/可靠性 | 事务、持久化、ACK机制 | QoS 0/1/2分级 | 基础ACK支持 |
网络适应性 | 稳定网络环境 | 高(适应弱网) | 一般 |
典型应用 | 金融交易、ERP系统 | 传感器网络、智能设备 | Web应用、实时仪表盘 |
实现复杂度 | 高 | 中 | 低 |
- AMQP:适合企业级复杂系统,提供灵活路由和高可靠性。
- MQTT:为物联网优化,轻量且支持弱网环境。
- STOMP:适用于简单交互场景,尤其是浏览器与后端的实时通信。
在RabbitMQ等消息中间件中,AMQP通常为默认支持,而MQTT和STOMP需通过插件启用。选择协议时需根据场景需求权衡功能、复杂度与性能。