6.3 KiB
tags, create time, update time
| tags | create time | update time | |||||||
|---|---|---|---|---|---|---|---|---|---|
|
2026-08-08 18:50 | 2026-08-08 18:50 |
Exchange 路由机制
概述
Exchange(交换机)是 RabbitMQ 消息路由的核心组件,充当生产者与队列之间的中间层。生产者在发送消息时指定 Exchange 名称和 routing key,RabbitMQ 根据 Exchange 类型和路由规则将消息分发到一个或多个 Queue。掌握四种内置 Exchange 类型以及插件扩展的延迟交换能力,是设计可靠消息系统的基础。
核心原理
四种内置 Exchange 类型
Direct Exchange — 精确匹配
Direct Exchange 使用完全匹配原则:routing key 必须与 Queue 绑定到 Exchange 时的 binding key 完全一致,消息才会被投递。
sequenceDiagram
participant P as 生产者
participant E["Direct Exchange"]
participant Q1["Queue A (key: order.create)"]
participant Q2["Queue B (key: order.* )"]
participant Q3["Queue C (key: *.pay)"]
P->>E: 发送消息<br/>routing key: "order.create"
E->>Q1: 匹配成功,投递
Note over E,Q1: "order.create" == "order.create"
E->>Q2: 匹配失败
Note over E,Q2: "order.create" ne "order.*"
E->>Q3: 匹配失败
Note over E,Q3: "order.create" ne "*.pay"
关键特征:一对一或一对多投递(多个 Queue 绑定了相同的 binding key)。这是最常用也最可预测的路由方式。
Fanout Exchange — 广播模式
Fanout Exchange 忽略 routing key,将消息投递到所有绑定到该 Exchange 的 Queue。每次收到消息就是群发。
sequenceDiagram
participant P as 生产者
participant E["Fanout Exchange"]
participant Q1["订单队列"]
participant Q2["日志队列"]
participant Q3["通知队列"]
P->>E: 发送消息<br/>routing key: (任意值)
E->>Q1: 广播投递
E->>Q2: 广播投递
E->>Q3: 广播投递
Note right of E: 忽略 routing key<br/>全部投递
典型场景:事件广播、配置刷新、缓存失效通知。不需要关心消息内容被哪些消费者处理。
Topic Exchange — 通配符匹配
Topic Exchange 是最灵活的路由模式,支持通配符匹配:
*(星号)匹配恰好一个词#(井号)匹配零个或多个词
词之间以点号 . 分隔。匹配规则示例:
| routing key | binding key | 是否匹配 |
|---|---|---|
quick.orange.fox |
*.orange.* |
是 |
quick.orange.fox |
quick.*.fox |
是 |
quick.brown.fox |
*.orange.* |
否 |
quick.orange.male.rabbit |
# |
是(匹配所有) |
lazy.orange.cat |
lazy.# |
是 |
sequenceDiagram
participant P as 生产者
participant E["Topic Exchange"]
participant Q1["Queue: *.create"]
participant Q2["Queue: *.pay.*"]
participant Q3["Queue: #"]
P->>E: routing key: "order.create"
E->>Q1: 匹配 "*" -> 投递
E->>Q2: "order.pay.*" ne "*.pay.*" -> 不投递
E->>Q3: "#" -> 投递
P->>E: routing key: "order.pay.success"
E->>Q1: "*.create" ne "order.pay.success" -> 不投递
E->>Q2: 匹配 "*.pay.*" -> 投递
E->>Q3: "#" -> 投递
Headers Exchange — 基于属性匹配
Headers Exchange 忽略 routing key,通过检查消息的 headers 属性(key-value 对)来决定路由。可以设置 match 参数:all(所有 header 都匹配)或 any(任一 header 匹配即可)。
Warning
Headers Exchange 性能较差且灵活性不如 Topic Exchange,官方文档明确标注"不推荐在生产中使用"。应优先选择 Topic Exchange。
死信交换机的特殊绑定
Dead Letter Exchange(DLX)本质上也是一个普通 Exchange,只是通过队列属性间接触发。当队列中的消息满足以下条件之一时,会被重新路由到 DLX:
- 消息被 nack 且不重新入队(
requeue=false) - 消息 TTL 过期
- 队列长度限制已满
# 队列声明时指定 DLX
queue:
name: "order.processing"
arguments:
x-dead-letter-exchange: "dead-letter-exchange"
x-dead-letter-routing-key: "order.dead"
延迟交换插件(x-delayed-message)
RabbitMQ 本身不提供延迟消息功能,需要安装 rabbitmq_delayed_message_exchange 插件后使用自定义 Exchange 类型 x-delayed-message。它通过消息的 x-delay header 控制投递时机。
// Go 代码示例:声明延迟 Exchange
// (amqp.go 库简化写法)
args := amqp.Table{
"x-delayed-type": "direct", // 内部转发使用的 Exchange 类型
}
ch.ExchangeDeclare(
"delayed.exchange", // name
"x-delayed-message", // type
true, // durable
false, // auto-deleted
false, // internal
false, // no-wait
nil, // args
args, // 自定义参数
)
构建消息时设置 x-delay header(单位毫秒):
// Go 代码示例:带延迟头的消息
msg := amqp.Publishing{
Body: []byte(`{"orderId":"123"}`),
Headers: amqp.Table{
"x-delay": uint32(60000), // 延迟 60 秒
},
}
Tip
面试常考点:RabbitMQ 原生不支持延迟消息。常见替代方案有定时任务轮询、Redis ZSet 定时弹出、或使用 Kafka 的分区时间排序特性。但在高可靠性场景中,x-delayed-message 插件是最直接可靠的方案。
实践场景
| 场景 | 推荐 Exchange | 原因 |
|---|---|---|
| 订单创建通知下游 | Direct | 精确控制消息去向 |
| 全局缓存失效广播 | Fanout | 所有服务实例都需要收到 |
| 日志分级收集(info/error/warn) | Topic | 按级别前缀灵活路由 |
| 支付回调不同金额段分流 | Topic | 按 amount.linux``amount.high 等维度拆分 |
| 超时未支付取消订单 | x-delayed-message | 精确控制延迟投递时间 |
| 死信消息归档 | Direct + DLX 属性 | 标准化异常流程处理 |
Tip
秋招面试技巧:当被问到"如何设计一个支持多种消息类型的路由系统"时,优先考虑 Topic Exchange 的通配符能力,而非为每种类型创建独立的 Direct Exchange。Topic Exchange 天然支持层级化路由,运维上更简洁。