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。三种常用交换机已介绍两种,下一章讲最灵活的主题交换机。

笔记加载中…