发布&订阅模型
1. 什么是发布/订阅模型
Section titled “1. 什么是发布/订阅模型”发布/订阅模型(Publish/Subscribe) 是在工作消息队列基础上引入了交换机(Exchange) 的消息传递机制。生产者不再直接向队列发送消息,而是发送给交换机,由交换机根据类型和绑定规则将消息路由到一个或多个队列,从而实现一条消息被多个消费者接收。
与前两种模型的对比:
| 基本消息队列 | 工作消息队列 | 发布/订阅模型 | |
|---|---|---|---|
| 消费者数量 | 1 个 | 多个(竞争) | 多个(各自独立) |
| 消息分配 | — | 一条消息只给一个 Worker | 一条消息可给多个消费者 |
| 核心组件 | Queue | Queue | Exchange + Queue + Binding |
| 典型场景 | 简单传递 | 任务分发 | 广播通知、事件驱动 |
2. 核心概念
Section titled “2. 核心概念”- Exchange(交换机):接收生产者消息,根据类型和绑定规则路由到队列。生产者只与交换机交互,不直接操作队列。
- Queue(队列):存储消息,消费者从队列拉取消息。
- Binding(绑定):连接交换机与队列的规则,可附带 Binding Key 用于路由匹配。
- Routing Key(路由键):生产者发送消息时携带的标识,交换机根据它决定消息去哪个队列。
- Publisher(发布者):将消息发送到交换机的应用。
- Subscriber(订阅者):从队列中消费消息的应用。
┌──Binding──▶ Queue1 ──▶ Consumer1Publisher ──▶ Exchange ─┤ └──Binding──▶ Queue2 ──▶ Consumer23. Exchange 类型
Section titled “3. Exchange 类型”3.1. Fanout Exchange(扇出)
Section titled “3.1. Fanout Exchange(扇出)”将消息广播到所有绑定的队列,完全忽略 Routing Key。
Exchange(fanout) ──▶ Queue1 ──▶ Consumer1 ──▶ Queue2 ──▶ Consumer2 ──▶ Queue3 ──▶ Consumer3适用场景:系统广播通知(如全体用户推送、缓存刷新通知)。
3.2. Direct Exchange(直连)
Section titled “3.2. Direct Exchange(直连)”根据 Routing Key 精确匹配 Binding Key,只有匹配的队列才会收到消息。
消息(key=error) ──▶ Exchange(direct) ──▶ error队列 ──▶ 错误日志消费者消息(key=info) ──▶ Exchange(direct) ──▶ info队列 ──▶ 普通日志消费者适用场景:按日志级别分发(error/warn/info)、按业务类型路由。
3.3. Topic Exchange(主题)
Section titled “3.3. Topic Exchange(主题)”支持通配符匹配 Routing Key,规则如下:
| 通配符 | 含义 |
|---|---|
* | 匹配一个单词 |
# | 匹配零个或多个单词 |
Routing Key: order.created.shanghaiBinding Key: order.* ✗ 不匹配(只能匹配一个词)Binding Key: order.# ✓ 匹配Binding Key: *.created.* ✓ 匹配适用场景:多维度路由,如按地区+业务类型组合分发消息。
3.4. Headers Exchange(头部)
Section titled “3.4. Headers Exchange(头部)”根据消息的 Header 键值对匹配队列,完全忽略 Routing Key。匹配模式分两种:
x-match: all:所有 Header 都匹配才路由x-match: any:任一 Header 匹配即路由
适用场景:路由逻辑复杂、无法用字符串 Key 描述的场景(实际项目中较少使用)。
3.5. Default Exchange(默认)
Section titled “3.5. Default Exchange(默认)”RabbitMQ 内置的特殊 Direct Exchange,名称为空字符串。每个队列自动以队列名作为 Binding Key 绑定到它,无需手动声明绑定关系。
适用场景:基本消息队列和工作消息队列底层默认使用的就是它。
3.6. Exchange 类型速查
Section titled “3.6. Exchange 类型速查”| 类型 | 路由方式 | 是否用 Routing Key | 典型场景 |
|---|---|---|---|
| Fanout | 广播所有绑定队列 | ✗ | 全局通知、缓存刷新 |
| Direct | 精确匹配 | ✓ | 日志分级、任务路由 |
| Topic | 通配符匹配 | ✓ | 多维度路由 |
| Headers | Header 键值对匹配 | ✗ | 复杂属性路由 |
| Default | 队列名即路由键 | ✓ | 简单点对点(内置) |
4. 优缺点
Section titled “4. 优缺点”优点:
- 松耦合:发布者和订阅者无需感知对方,降低系统耦合度
- 可扩展:动态添加订阅者无需修改发布者代码
- 广播能力:一条消息可同时触达多个下游系统
- 异步处理:订阅者异步消费,提升系统响应能力
缺点:
- 消息丢失风险:订阅者离线期间若未持久化,可能错过消息
- 顺序不保证:多个消费者并发消费时,消息处理顺序可能不一致
- 重复消费:网络异常等场景下消息可能重复投递,需消费者做幂等处理
- 性能压力:订阅者过多时,消息扇出会带来较大的 I/O 和内存开销