RabbitMQ 的 Direct、Topic、Fanout 交换机有什么区别?消息怎样找到队列?
以下对话为教学模拟,不是真实面经。
🧑💻 面试官:RabbitMQ 消息发送到哪里?
🙋♂️ 我:发送到队列,消费者从队列取。
🧑💻 面试官:应用一般先把消息发给哪个对象?一个消息需要送到多个队列,谁决定?
先把交换机、绑定和队列分开:交换机决定路由,队列负责保存等待消费的消息。
面试速答(60 秒版)
RabbitMQ 中,生产者通常把消息发布到交换机,交换机根据类型、routing key 和绑定关系,把消息路由到零个或多个队列。
Direct 交换机主要按 routing key 与绑定键精确匹配。Topic 使用分段模式匹配,星号匹配一个词,井号匹配零个或多个词。Fanout 则把消息送到所有绑定队列,不依靠 routing key 区分。
同一个交换机绑定多个队列,可以让多个业务分别消费一份消息;同一个队列的多个消费者,通常是竞争处理队列里的消息,不是每个消费者都收到一份。
还要处理没有匹配队列的情况。交换机存在,不代表消息一定已经被目标消费者处理。

知识点详解:一条消息怎样找到应该进入的队列
消息先路由,再等待消费
咱们假设订单系统发布“支付完成”。库存服务和通知服务都需要知道这个事件。
生产者把消息发给交换机,交换机根据绑定关系决定进入哪些队列。库存服务拥有自己的队列,通知服务也有自己的队列,这样两边可以独立消费。
RabbitMQ 的交换机文档说明了交换机与路由机制。不能把交换机画成保存全部待消费消息的数据库;等待消费的消息通常由队列承担。
默认交换机有特殊行为,可以通过队列名进行相应路由,但这不等于一般发布模型没有交换机。
Direct,适合明确的精确分类
假设 routing key 为 order.paid。绑定键也是 order.paid 的队列会匹配;绑定 order.cancelled 的队列不会因为同属订单主题就收到消息。
如果两个队列都用 order.paid 绑定,它们都可以收到这条消息。因此,Direct 不是“一条消息只能给一个队列”。
具体路由仍依赖绑定存在。交换机类型本身不能替你创建业务队列或保证消费者可用。
Topic,把分类组织成带点的词
Topic 的 key 可以是 order.cn.paid。绑定 order.*.paid 能匹配其中的国家位置,但星号只能匹配一个词。
绑定 order.# 可以匹配 order 后面的零个或多个词。井号与星号的区别不只是“长度不同”,而是按点分隔的词数量匹配。
例如 order.* 不能直接匹配 order.cn.paid,因为后面有两个词。把 Topic 理解成任意字符串正则,会在这种地方答错。

Fanout,按绑定广播,不按 key 分类
如果某个事件需要送给所有订阅服务,可以考虑 Fanout。它把消息路由给所有绑定队列,routing key 不用于这种分类判断。
但是,广播发生在队列这一层。若一个队列有三个消费者,通常由它们竞争处理,而不是自动得到三份独立副本。
因此,库存和通知需要各自收到一份,通常应该各有队列;同一个业务需要增加处理能力,才考虑在它的队列后增加消费者。

没有匹配队列,不能装作成功投递
生产者发布后可能没有任何匹配队列。需要依据协议和配置处理未路由情况,例如采用 mandatory 返回或备用交换机等机制。
发布确认、进入队列和消费者处理完成也是不同阶段。RabbitMQ 的确认说明区分了相关责任。不能看到 broker 确认,就声称业务已经完成。
验证时可以用同一 routing key 测不同绑定,检查实际进入哪些队列,再模拟一个没有绑定的场景。路由表正确以后,再讨论持久性、消费确认和重试;这些不由交换机类型单独保证。
面试官继续追问
Direct 和 Fanout 都能进入多个队列,差别是什么?
Direct 要满足精确绑定条件,Fanout 主要按是否绑定广播。结果都可能是多个队列,但选择条件不同。
Topic 的 # 可以匹配空吗?
可以匹配零个词,也能匹配多个词,需要结合完整绑定模式判断。
一个队列多个消费者算广播吗?
通常不算,它们竞争处理队列消息。独立订阅者需要各自的队列,才能各自保留消费进度。
面试速记卡
- 主链路:生产者 → 交换机 → 绑定匹配 → 队列 → 消费者。
- Direct:routing key 精确匹配绑定键。
- Topic:星号一个词,井号零个或多个词。
- Fanout:向绑定队列广播,不靠 routing key 分类。
- 责任边界:路由、入队与业务处理完成不是同一件事。
公司面试真题
这道题暂未收录可核验的公司真题来源。你可以先阅读本文解析,或浏览已收录的公司面试真题。
浏览公司面试真题 →