RabbitMQ:解锁高效消息传递的密码[特殊字符]
目录
一、RabbitMQ 核心概念
1.1整体框架
1.2元素详解
1.2.1 生产者(Producer)&消费者(Consumer)
1.2.2 交换机(Exchange)
①fanout (广播型)
②direct (直连型)
③topic型(支持模糊匹配型)
④headers (不推荐使用)
1.2.3 消息队列(Queue)
1.2.4 消息中间站中间节点(Broker)
1.2.5 绑定键(Binding Key)&&路由键(Routing Key)
💡总结
二、其他队列概述
2.1 死信队列
导致死信的几种原因:
2.2 延迟队列(Delay Queue)
2.3 优先级队列(Priority Queue)
🔍延伸思考
🧠在消息队列:数字化通信的高效纽带-CSDN博客 文章中已经对消息队列有了基础的理解
RabbitMQ 是一个开源的消息代理(Message Broker),实现了 高级消息队列协议(AMQP),用于在分布式系统中实现 异步通信。它解耦了消息的生产者(发送方)和消费者(接收方),使系统更灵活、可扩展。
一、RabbitMQ 核心概念
💡RabbitMQ主要涉及以下元素:
- 生产者(Producer):发送消息的应用。
- 消费者(Consumer):接收并处理消息的应用。
- 消息队列(Queue):存储消息的缓冲区(默认先进先出)。
- 交换机(Exchange):接收生产者消息,并按规则路由到队列(类似邮局)。
- 绑定(Binding):定义交换机和队列之间的关系(路由规则)。
- 消息(Message):包含头部(headers)、正文(body)和元数据。
RabbitMQ 整体上是一个生产者与消费者模型,主要负责接收、存储和转发消息。
可以把消息传递的过程想象成:当你将一个包裹送到邮局,邮局会暂存并最终将邮件通过邮递员送到收件人的手上,RabbitMQ就好比由邮局、邮箱和邮递员组成的一个系统。从计算机术语层面来说,RabbitMQ 模型更像是一种交换机模型。
1.1整体框架
1.2元素详解
1.2.1 生产者(Producer)&消费者(Consumer)
- Producer(生产者) :生产消息的一方(寄信人)
- Consumer(消费者) :消费消息的一方(邮件收件人)
消息一般由 2 部分组成:消息头(或者说是标签 Label)和 消息体。消息体也可以称为 payLoad ,消息体是不透明的,而消息头则由一系列的可选属性组成,这些属性包括 routing-key(路由键)、priority(相对于其他消息的优先权)、delivery-mode(指出该消息可能需要持久性存储)等。生产者把消息交由 RabbitMQ 后,RabbitMQ 会根据消息头把消息发送给感兴趣的 Consumer(消费者)
1.2.2 交换机(Exchange)
在 RabbitMQ 中,消息并不是直接被投递到 Queue(消息队列) 中的,中间还必须经过 Exchange(交换器) 这一层,Exchange(交换器) 会把我们的消息分配到对应的 Queue(消息队列) 中。
💡生产者 → 交换机
如果这一步失败(比如交换机不存在、网络中断),消息不会进入系统,而是直接被丢弃或返回给生产者(取决于 publisher confirm 和 mandatory 的设置),不会进入死信队列(死信队列后面会讲)。
RabbitMQ 的 Exchange(交换器) 有4种类型,不同的类型对应着不同的路由策略:direct(默认),fanout, topic, 和 headers,不同类型的Exchange转发消息的策略有所区别。
①fanout (广播型)
fanout 类型的Exchange路由规则非常简单,它会把所有发送到该Exchange的消息路由到所有与它绑定的Queue中,不需要做任何判断操作,所以 fanout 类型是所有的交换机类型里面速度最快的。fanout 类型常用来广播消息。
②direct (直连型)
direct 类型的Exchange路由规则也很简单,它会把消息路由到那些 Bindingkey 与 RoutingKey 完全匹配(绑定键==路由键)的 Queue 中。
即:如果发送消息的时候设置路由键为“warning”,那么消息会路由到 Queue1 和 Queue2。如果在发送消息的时候设置路由键为"Info”或者"debug”,消息只会路由到Queue2。如果以其他的路由键发送消息,则消息不会路由到这两个队列中。
direct 类型常用在处理有优先级的任务,根据任务的优先级把消息发送到对应的队列,这样可以指派更多的资源去处理高优先级的队列。
③topic型(支持模糊匹配型)
direct类型的交换器严格的匹配方式在很多情况下不能满足实际业务的需求。所以topic类型的交换器在匹配规则上进行了扩展,它与 direct 类型的交换器相似,也是将消息路由到 BindingKey 和 RoutingKey 相匹配的队列中,但这里的匹配规则有些不同,它约定:
- RoutingKey 与 BindingKey 进化成都是以点号“.”分割的单词串;
- BindingKey 中可以存在两种特殊字符串"*"和"#",用于做模糊匹配,其中"*"用于匹配一个单词,"#"用于匹配多个单词(可以是零个)。
所以根据规则可知:
- 路由键为 “com.rabbitmq.client” 的消息会同时路由到 Queuel 和 Queue2;
- 路由键为 “com.hidden.client” 的消息只会路由到 Queue2 中;
- 路由键为 “com.hidden.demo” 的消息只会路由到 Queue2 中;
- 路由键为 “java.rabbitmq.demo” 的消息只会路由到Queuel中;
- 路由键为 “java.util.concurrent” 的消息将会被丢弃或者返回给生产者(需要设置 mandatory 参数),因为它没有匹配任何路由键。
④headers (不推荐使用)
不看 routing-key,只看 消息 headers。
绑定队列时写一组 Key-Value;消息里 Key-Value完全一致才命中。
可加 x-match = any/all
:
• any
只要有一个键值匹配即可;
• all
(默认)必须全部键值都匹配。
所以说这个类型的交换机性能极差,不推荐使用。
1.2.3 消息队列(Queue)
Queue(消息队列) 用来保存消息直到发送给消费者。它是消息的容器,也是消息的终点。一个消息可投入一个或多个队列。消息一直在队列里面,等待消费者连接到这个队列将其取走。
RabbitMQ 中消息只能存储在 队列 中,这一点和 Kafka 这种消息中间件相反。Kafka 将消息存储在 topic(主题) 这个逻辑层面,而相对应的队列逻辑只是topic实际存储文件中的位移标识。 RabbitMQ 的生产者生产消息并最终投递到队列中,消费者可以从队列中获取消息并消费。
多个消费者可以订阅同一个队列,这时队列中的消息会被平均分摊(Round-Robin,即轮询)给多个消费者进行处理,而不是每个消费者都收到所有的消息并处理,这样避免的消息被重复消费。
RabbitMQ 不支持队列层面的广播消费,如果有广播消费的需求,需要在其上进行二次开发,这样会很麻烦,不建议这样做。
💡总结
消息只能落到队列,队列是 RabbitMQ 的物理终点。
一个队列可被多个消费者订阅,消息以轮询的方式均摊,天然避免重复消费。
队列本身无广播能力,如需“每人一条”只能用多个队列或二次开发,不推荐。
1.2.4 消息中间站中间节点(Broker)
💡RabbitMQ Broker ≈ 一个独立的 RabbitMQ 进程/容器/服务器节点,负责接收连接、管理交换机、队列和消息的核心服务单元。
1.2.5 绑定键(Binding Key)&&路由键(Routing Key)
维度 | 路由键 (Routing Key) | 绑定键 (Binding Key) |
---|---|---|
谁产生 | 由生产者在发送消息时设置 | 由管理员/消费者在“把队列绑定到交换机”时设置 |
作用对象 | 消息本身 | 队列与交换机的绑定关系 |
作用时机 | 消息到达交换机时,交换机用它来做路由 | 交换机收到消息后,用它与消息中的路由键做匹配 |
使用场景 | 只在发送消息时用到 | 只在创建绑定时用到 |
格式限制 | 任意字符串(具体规则取决于交换机类型) | 与路由键格式一致; |
举个例子 | 生产者发消息时:routingKey = "order.paid" | 消费者绑定时:bindingKey = "order.*" |
💡总结
1.路由键(Routing Key)--消息的固有属性
- 是消息自带的一个字段,在创建/发布消息时由生产者指定,是消息本身的属性之一。
- 相当于写在信封上的“收件人线索”,消息一出生就带着它。
2.绑定键(Binding Key)--交换机侧的路由规则
- 不是消息的一部分,而是队列在绑定到交换机时设立的匹配规则。
- 相当于“邮局分拣员”手里的“收件条件表”,用来决定哪些信封(消息)可以放进哪个投递箱(队列)。
二、其他队列概述
2.1 死信队列
DLX,全称为 Dead-Letter-Exchange
,死信交换器,死信邮箱。当消息在一个队列中变成死信 (dead message
) 之后,它能被重新发送到另一个交换器中,这个交换器就是 DLX,绑定 DLX 的队列就称之为死信队列。
导致死信的几种原因:
- 消息被拒(
Basic.Reject /Basic.Nack
) 且requeue = false
。- 消息 TTL 过期。
- 队列满了,无法再添加。
简而言之,就是交换机的消息无法抵达正常队列时,就会进入死信队列。
2.2 延迟队列(Delay Queue)
消息不立即投递,而是等待指定的“延迟时间”到期后才对消费者可见。
2.3 优先级队列(Priority Queue)
队列中的消息按优先级字段排序,优先级高的消息先被消费,低优先级的后出队。
特性 | 原生支持 | 实现思路 | 备注 |
---|---|---|---|
优先级队列 | ✅ | 队列声明时加 x-max-priority=N ;消息加 priority 属性(0-N) | 性能随优先级级别增加而下降 |
延迟队列 | ❌(3.12 起实验性支持) | 需借助插件或“TTL+DLX”技巧 | 官方推荐 rabbitmq-delayed-message-exchange 插件 |
🔍延伸思考
- 怎么验证消息丢没丢?
- 如何保障消息顺序性?
- 如何保障消息事务性,保证消息不重复消费?