Skip to content

RabbitMQ路由模式

简单队列模式

简介

RabbitMQ的简单路由模式(Simple Work Mode)是其最基础的消息传递模型,适用于单一生产者和消费者的场景。 simple-model

核心组件

  • 生产者
    发送消息的应用程序
  • 队列
    存储消息的缓冲区,消息在队列中等待被消费
  • 消费者
    接收并处理消息的应用程序
  • 默认交换机
    隐式路由消息到指定队列,生产者通过指定队列名(Routing key)直接发送消息

default-exchange默认交换机是直连交换机的一种特例,它默认绑定到所有已被声明的队列,其路由键等于队列名。不能显示的将该交换机与队列进行绑定或解绑,该交换机也不能被删除

工作流程

  • 生产者发送消息
    生产者连接到RabbitMQ,声明一个队列
    消息通过默认交换机(无需显示声明)发送到指定队列,Routing key 为队列名
  • 队列存储消息
    队列暂存消息,直到消费者处理完成,消息按先进先出(FIFO)的顺序传递
  • 消费者接收消息
    消费者订阅队列,RabbitMQ将消息分发给消费者

工作队列模式

简介

RabbitMQ的工作队列模式(Work Queues),有时也被称为任务队列(Task Queues)。一个或多个消费者可以异步地从队列中取出任务并执行它们。 work-queue-model

TIP

  • 工作队列模式中消息允许多个消费者消费,即使某个消费者是在消费半途加入的,只要成功监听到队列,就会接收到后续分发的消息

工作流程

  • 生产者发送消息
    生产者连接到RabbitMQ,声明一个队列
    消息通过默认交换机(无需显示声明)发送到指定队列,Routing key 为队列名
  • 队列存储消息
    队列暂存消息,直到消费者处理完成,消息按先进先出(FIFO)的顺序传递
  • 消费者接收消息
    消费者订阅队列,RabbitMQ将消息分发给消费者

工作队列的工作流程与简单队列的工作流程类似,只是简单队列的消息是被一个消费者消费,而工作队列的消息是被多个消费者消费。

消息分发模式

工作队列模式中,支持的消息分发模式有两种,分别是轮询分发公平分发

  • 轮询分发
    • 含义
      消息按照顺序依次分配给所有消费者,不考虑消费者的处理能力或当前负载
      • 例如:有 2 个消费者(C1、C2),消息 M1~M4 将按 C1→M1, C2→M2, C1→M3, C2→M4 的顺序分发。
      • 问题:若某些消息处理耗时较长,可能导致消费者负载不均(如 C1 积压,C2 空闲)。
    • 配置
      • 无需额外配置,RabbitMQ 自动启用轮询分发。
  • 公平分发
    • 含义
      消息根据消费者的处理能力动态分配,只有消费者空闲时才会收到新消息
      • 例如:C1 处理 M1 耗时 5 秒,C2 处理 M2 耗时 1 秒。C2 处理完 M2 后,会立即接收 M3,而 C1 仍在处理 M1。
      • 优势:避免消费者因处理慢导致消息积压,提高整体吞吐量。
    • 核心机制 prefetch_count 参数:控制消费者未确认(unacked)消息的最大数量。
      • 若 prefetch_count = 1,消费者每次最多持有 1 条未处理完的消息,处理完后才会接收下一条消息。
      • 若 prefetch_count = 0,表示无限制,RabbitMQ 会一次性推送所有消息到消费者(实际为轮询)
    • 配置
      application.properties
      java
      spring.rabbittmq.listener.simple.prefetch=1 # 关键配置,每次只分发一条消息

轮询分发 VS 公平分发

特性轮询分发(Round Robin)公平分发(Fair Dispatch)
分发逻辑按顺序依次分配给所有消费者动态分配给空闲的消费者
负载均衡效果可能不均衡(依赖消息处理时间)更均衡(优先分配给空闲消费者)
适用场景消息处理时间相近的任务消息处理时间差异大的任务(如耗时任务)
配置参数无需配置(默认行为)需设置 prefetch_count=1
吞吐量可能较低(消费者可能空闲)更高(充分利用消费者资源)

发布/订阅模式

简介

RabbitMQ 的发布订阅模式(Publish/Subscribe Pattern,简称Pub/Sub),消息生产者发送消息到指定类型的交换机(扇形交换机 Fanout Exchange),而不是直接发送给特定的消息队列。 然后,这个交换机会将接收到的消息广播给所有绑定到它的队列。这意味着任何数量的消费者都可以接收和处理这些消息,只要它们通过相应的队列绑定到了该交换器。 publish-sub

工作流程

  • 生产者发送消息
    生产者将消息发送给一个指定类型的交换机(扇形交换机 Fanout Exchange)。
  • 交换机分发消息到队列
    在发布订阅模式下,使用扇形交换器,它会忽略路由键并将消息广播给所有已绑定的队列。
    每个绑定了该交换器的队列都会收到这条消息的一个副本。
  • 消费者消费消息
    消费者从各自的队列中读取消息,并进行处理。

路由模式

简介

RabbitMQ 的路由模式(Routing Pattern),允许消息生产者发送消息到指定类型的交换机(直连交换机 Direct Exchange),然后根据特定的规则将消息发送到一个或多个指定的消息队列。

与发布订阅模式不同,路由模式允许更精确地控制哪些队列会接收到消息。这是通过使用直接(Direct Exchange)交换器和绑定键(Binding key)来实现的。如果某个队列与直连交换机的绑定键(Bind key)与某条消息的路由键(Routing key)完全相同,则该队列将收到该条消息的副本。 routing-model

工作流程

  • 生产者发送消息
    生产者向直连交换机发送一条消息,并指定一个路由键。
  • 交换机分发消息
    直连交换器检查所有与之绑定的队列的绑定键。
    如果某队列的绑定键与消息的路由键完全匹配,则该队列将收到该条消息的副本。
  • 消费者接收消息
    消费者从其监听的队列中接收并处理消息。

主题模式

简介

RabbitMQ的主题模式(Topic Pattern)是一种更为灵活的消息路由机制,它基于模式匹配来决定消息的流向。与路由模式下的直连交换机相比,主题交换机允许使用通配符来匹配路由键,从而实现更复杂的消息路由逻辑。这种模式非常适合用于需要根据多个条件或模糊匹配规则来分发消息的应用场景。 topic-model

工作流程

  • 生产者发送消息
    生产者向主题交换机发送一条带有特定路由键的消息
  • 交换机分发消息
    主题交换机根据消息的路由键和所有绑定到它的队列的绑定键进行模式匹配
    如果某个队列的绑定键与消息的路由键匹配,则该消息会被路由到这个队列
  • 消费者接收消息
    消费者订阅队列,RabbitMQ将消息分发给消费者

匹配规则

  • 路由键必须是一串由点号分隔的单词列表,但单词数量没有限制。
  • 绑定键可以是确切的单词,也可以包含通配符 * 和 #,以支持更加灵活的匹配策略。
    例如:
    • 绑定键为 *.orange.*匹配任何中间单词为 orange 的路由键,如 quick.orange.rabbitlazy.orange.elephant
    • 绑定键为 lazy.# 可以匹配以 lazy 开头的任何路由键,包括 lazy 自身,以及 lazy.brownlazy.purple.giraffe 等。

头部模式

简介

RabbitMQ的头部路由模式(Headers Exchange)提供了一种基于消息头属性而非路由键来决定消息如何路由到队列的方法。这种模式为消息传递提供了更大的灵活性,因为它允许根据消息头中的任意属性进行匹配和路由,而不仅仅依赖于一个简单的字符串作为路由键。

匹配规则

当一条消息发送到头部交换器时,交换器会检查该消息的头部属性。 交换器然后尝试将这些头部属性与所有已绑定的队列的绑定参数进行匹配。 根据绑定参数中的 x-match 设置,决定是需要全部头部条件匹配还是只需要部分匹配。 如果匹配成功,则消息会被路由到相应的队列。

TIP

x-match 仅提供了 全有 或 全无 的选择,并不直接支持更复杂的组合逻辑,如“任意两个条件匹配”。

  • all:需要所有条件匹配
  • any:只需要至少一个条件匹配

如果需要任意两个条件匹配,例如,如果你有三个头部属性A、B和C,你希望任何两个匹配就可以,那么你可以创建三个绑定,分别是(A和B)、(A和C)、(B和C)。这样,如果消息满足任意两组条件,它就会被路由到该队列。

示例说明

假设你有两个队列 Q1 和 Q2:

  • Q1
    通过头部属性 format=pdf 和 type=report 与头部交换器绑定,且 x-match=all,意味着只有当消息同时包含这两个头部属性时,才会被路由到 Q1。
  • Q2
    通过头部属性 priority=high 或 type=alert 与头部交换器绑定,且 x-match=any,这意味着只要消息包含这两个头部属性中的任何一个,就会被路由到 Q2。

如果你发送一条带有如下头部属性的消息,这条消息将会被路由到 Q1 但不会被路由到 Q2。
因为虽然它包含了 type=report,但它并不满足 Q2 的任一绑定条件(即 priority=high 或 type=alert)。

头部属性
json
{
  "format":"pdf", 
  "type":"report", 
  "priority":"normal"
}

RPC模式

简介

RabbitMQ的RPC(Remote Procedure Call,远程过程调用)模式是一种通过消息队列实现分布式系统中服务间通信的方法。虽然RabbitMQ主要用于异步消息传递,但通过一些额外的设计,它也可以支持同步请求-响应模式,这正是RPC的核心思想。

核心概念

  • 客户端(Client)
    发起请求的一方,在RPC模式中扮演着请求者的角色。
  • 服务器(Server)
    接收请求并返回结果的一方,在RPC模式中是服务提供者。
  • 回调队列(Callback Queue)
    一个专门用于接收响应消息的临时队列,每个请求都会创建一个新的回调队列或者使用一个独有的队列来确保响应能够正确地返回给对应的请求者。
  • Correlation Id(关联ID)
    为了匹配请求和响应,客户端会在发送请求时生成一个唯一的correlationId,并将这个ID包含在请求消息中。服务器处理完请求后,在响应消息中也会带上这个correlationId,这样客户端就能识别出哪个响应对应哪个请求了。

工作流程

  • 客户端初始化
    客户端创建一个匿名、独占的回调队列,用于接收特定于该客户端的响应消息。
  • 发送请求
    客户端准备请求数据,并为请求分配一个唯一的correlationId。
    请求消息不仅包含实际的数据,还包括两个特殊的属性:replyTo(指定回调队列的名字)和correlationId(用于关联请求和响应)。
    客户端将请求发送到预定义的RPC请求队列。
  • 服务器处理
    服务器监听RPC请求队列,一旦收到请求就进行处理。
    处理完成后,服务器会将结果作为响应消息发送回客户端,响应消息会被发送到请求中的replyTo字段指定的队列,并且携带相同的correlationId。
  • 客户端接收响应
    客户端持续监听其回调队列,等待响应到达。
    当响应消息到达时,客户端根据correlationId确认这是对之前发出的某个请求的响应,并据此处理响应数据。