RabbitMQ 扇形交换机
fanout(扇形)交换机把收到的每条消息复制一份,广播给它绑定的所有队列——不看 routing key、不看 binding key。它实现的就是"发布/订阅":一次发布,所有订阅者都拿到。
路由语义
routing key 在 fanout 里完全被忽略,消息进入交换机就直接复制给每个绑定的队列,绑几个队列就复制几份:
Exchange: news.fanout(fanout)
发布消息(任意 routing key)
├─► 队列 A(体育订阅)
├─► 队列 B(科技订阅)
└─► 队列 C(财经订阅)
完整示例:广播通知
一个"系统公告"广播:发布一次,邮件、短信、站内信三套消费者各收一份:
import pika
conn = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
ch = conn.channel()
ch.exchange_declare(exchange='notice.fanout', exchange_type='fanout', durable=True)
# 三个队列全部绑定,binding key 写什么都无所谓
for q in ('notice.email.q', 'notice.sms.q', 'notice.im.q'):
ch.queue_declare(queue=q, durable=True)
ch.queue_bind(queue=q, exchange='notice.fanout', routing_key='')
# 发布时 routing key 随便给(如空串),照样全量广播
ch.basic_publish(exchange='notice.fanout', routing_key='', body=b'server upgrade at 02:00')
print('公告已广播') # 输出:公告已广播
conn.close()
Java 写法与第 7 章一致:channel.exchangeDeclare("notice.fanout", "fanout", true) 声明、queueBind 绑定、basicPublish 发布,片段需放进 main 方法中运行。
临时队列:后来者也能立即订阅
订阅方常用"随机名临时队列":队列名为空让服务端生成、exclusive=true,消费者断开队列即消失,不影响其他订阅者:
result = ch.queue_declare(queue='', exclusive=True) # 空名 → 服务端生成随机名
qname = result.method.queue
ch.queue_bind(queue=qname, exchange='notice.fanout', routing_key='')
典型应用场景
fanout 就是"一次发布、全部订阅",适合如下场景:
| 场景 | 说明 |
|---|---|
| 广播通知 | 公告、升级提示发给所有订阅方 |
| 缓存刷新 | 一条"数据已变更"广播,各服务副本同时清缓存 |
| 数据同步 | 主库变更广播给搜索、报表、数仓等多个消费组 |
| 配置下发 | 配置更新推送给所有在线节点 |
不适用场景提醒
fanout 不筛选任何东西,队列只要绑上来就全量收。因此"只想要一部分消息"(按级别、按地域、按事件类型)的场景不要用 fanout,那是 direct(第 8 章)或 topic(第 10 章)的活。另外广播前要想清楚谁在消费:没有消费者在线的队列,消息会一直堆积(除非配了 TTL 或死信)。
小结
fanout = 全量广播,键值无效。记住口诀:全量广播用 fanout,按类型分流用 direct,按模式匹配用 topic。三种常用交换机已介绍两种,下一章讲最灵活的主题交换机。