跳转到内容

发布&订阅模型


发布/订阅模型(Publish/Subscribe) 是在工作消息队列基础上引入了交换机(Exchange) 的消息传递机制。生产者不再直接向队列发送消息,而是发送给交换机,由交换机根据类型和绑定规则将消息路由到一个或多个队列,从而实现一条消息被多个消费者接收

与前两种模型的对比:

基本消息队列工作消息队列发布/订阅模型
消费者数量1 个多个(竞争)多个(各自独立)
消息分配一条消息只给一个 Worker一条消息可给多个消费者
核心组件QueueQueueExchange + Queue + Binding
典型场景简单传递任务分发广播通知、事件驱动
  • Exchange(交换机):接收生产者消息,根据类型和绑定规则路由到队列。生产者只与交换机交互,不直接操作队列。
  • Queue(队列):存储消息,消费者从队列拉取消息。
  • Binding(绑定):连接交换机与队列的规则,可附带 Binding Key 用于路由匹配。
  • Routing Key(路由键):生产者发送消息时携带的标识,交换机根据它决定消息去哪个队列。
  • Publisher(发布者):将消息发送到交换机的应用。
  • Subscriber(订阅者):从队列中消费消息的应用。
┌──Binding──▶ Queue1 ──▶ Consumer1
Publisher ──▶ Exchange ─┤
└──Binding──▶ Queue2 ──▶ Consumer2

将消息广播到所有绑定的队列,完全忽略 Routing Key

Exchange(fanout) ──▶ Queue1 ──▶ Consumer1
──▶ Queue2 ──▶ Consumer2
──▶ Queue3 ──▶ Consumer3

适用场景:系统广播通知(如全体用户推送、缓存刷新通知)。

根据 Routing Key 精确匹配 Binding Key,只有匹配的队列才会收到消息。

消息(key=error) ──▶ Exchange(direct) ──▶ error队列 ──▶ 错误日志消费者
消息(key=info) ──▶ Exchange(direct) ──▶ info队列 ──▶ 普通日志消费者

适用场景:按日志级别分发(error/warn/info)、按业务类型路由。

支持通配符匹配 Routing Key,规则如下:

通配符含义
*匹配一个单词
#匹配零个或多个单词
Routing Key: order.created.shanghai
Binding Key: order.* ✗ 不匹配(只能匹配一个词)
Binding Key: order.# ✓ 匹配
Binding Key: *.created.* ✓ 匹配

适用场景:多维度路由,如按地区+业务类型组合分发消息。

根据消息的 Header 键值对匹配队列,完全忽略 Routing Key。匹配模式分两种:

  • x-match: all:所有 Header 都匹配才路由
  • x-match: any:任一 Header 匹配即路由

适用场景:路由逻辑复杂、无法用字符串 Key 描述的场景(实际项目中较少使用)。

RabbitMQ 内置的特殊 Direct Exchange,名称为空字符串。每个队列自动以队列名作为 Binding Key 绑定到它,无需手动声明绑定关系。

适用场景:基本消息队列和工作消息队列底层默认使用的就是它。

类型路由方式是否用 Routing Key典型场景
Fanout广播所有绑定队列全局通知、缓存刷新
Direct精确匹配日志分级、任务路由
Topic通配符匹配多维度路由
HeadersHeader 键值对匹配复杂属性路由
Default队列名即路由键简单点对点(内置)

优点:

  • 松耦合:发布者和订阅者无需感知对方,降低系统耦合度
  • 可扩展:动态添加订阅者无需修改发布者代码
  • 广播能力:一条消息可同时触达多个下游系统
  • 异步处理:订阅者异步消费,提升系统响应能力

缺点:

  • 消息丢失风险:订阅者离线期间若未持久化,可能错过消息
  • 顺序不保证:多个消费者并发消费时,消息处理顺序可能不一致
  • 重复消费:网络异常等场景下消息可能重复投递,需消费者做幂等处理
  • 性能压力:订阅者过多时,消息扇出会带来较大的 I/O 和内存开销