跳到主要内容
版本: 4.1

AMQP 1.0

AMQP 1.0 自 RabbitMQ 4.0 版本起原生支持。

版本协商

RabbitMQ 原生支持 AMQP 1.0 和 AMQP 0.9.1,无需任何额外的插件。

默认情况下,RabbitMQ 监听端口 5672,接受 AMQP 1.0 和 AMQP 0.9.1 的连接

在建立 TCP 或 TLS 连接之后,以及发送任何 AMQP 帧之前,客户端会发送一个协议头,表明它想使用 AMQP 1.0 还是 AMQP 0.9.1,如 2.2 节版本协商中所述。

对于 AMQP 1.0 连接,RabbitMQ 要求使用简单身份验证和安全层 (SASL),如 5.3 节 SASL 中所述。如果客户端不使用 SASL,RabbitMQ 将拒绝连接,如图 2.13:协议 ID 拒绝示例所示。

协议互操作性

RabbitMQ 支持跨不同协议发布和消费消息,这需要协议转换

当使用 AMQP 1.0 发布消息时,所有目标队列类型(经典队列仲裁队列)都以其原始 AMQP 1.0 格式存储消息。如果稍后使用 AMQP 1.0 消费消息,则无需协议转换。此外,根据 AMQP 1.0 规范的要求,RabbitMQ 确保裸消息的不可变性。这允许客户端不仅可以对消息体设置消息哈希、校验和和数字签名,还可以对属性应用程序属性部分进行设置。

虚拟主机

RabbitMQ 通过虚拟主机支持逻辑多租户。

如果连接应用程序没有显式指定虚拟主机,则连接将使用在 rabbitmq.conf 中配置的 default_vhost

default_vhost = /

AMQP 1.0 客户端可以通过在 open 帧中的 hostname 字段值前加上 vhost: 来连接到不同的虚拟主机

例如,要连接到名为 tenant-1 的虚拟主机,客户端将 hostname 字段设置为 vhost:tenant-1

地址

AMQP 1.0 地址决定了消息发送到哪里或从哪里消费。AMQP 地址指向哪个内部对象以及如何解析 AMQP 地址,AMQP 1.0 规范没有定义。不同的 AMQP 1.0 代理可以选择以不同的方式解释提供的地址。

RabbitMQ 实现了强大而灵活的 AMQ 0.9.1 模型,包括交换机队列绑定。因此,与 RabbitMQ 通信的 AMQP 客户端将消息发送到交换机,并从队列消费消息。因此,RabbitMQ 理解和解析的 AMQP 地址包含交换机名称、队列名称和路由键。

RabbitMQ 4.0 引入了一种新的 RabbitMQ 特定的 AMQP 地址格式,v2。旧的 RabbitMQ 3.x 地址格式称为 v1。

重要

AMQP 客户端应使用地址格式 v2。

地址格式 v1 在 RabbitMQ 4.0 中已被弃用,并且在未来的 RabbitMQ 版本中将不再支持。格式 v1 是否仍然受支持取决于已弃用的功能标志 amqp_address_v1,该标志在 RabbitMQ 4.0 中的弃用阶段为 permitted_by_default

地址 v2

本节定义新的 v2 地址格式。

目标地址 v2

可能的 v2 目标地址格式有

  1. /exchanges/:exchange/:routing-key
  2. /exchanges/:exchange
  3. /queues/:queue
  4. <null>

前三种格式是 字符串

第一种格式 /exchanges/:exchange/:routing-key 导致给定链接上的所有消息都以路由键 :routing-key 发送到交换机 :exchange

第二种格式 /exchanges/:exchange 导致给定链接上的所有消息都以空路由键 "" 发送到交换机 :exchange。这对于忽略路由键的交换机类型很有用,例如 fanout 交换机或 headers 交换机。

在前两种格式中的任何一种中设置默认交换机 "" 都是不允许的。请改用第三种格式。

第三种格式 /queues/:queue 导致给定链接上的所有消息都发送到队列 :queue
队列必须存在。在内部,此队列目标仍使用默认交换机。因此,用户需要对交换机 amq.default 具有写入权限。

前 3 种格式要求给定链接上的所有消息的目标地址都相同。如果需要在同一链接上的不同消息设置不同的交换机、路由键或队列,请使用第 4 种格式。

第 4 种格式是 AMQP null 值。正如 AMQP 扩展 使用 AMQP 匿名 Terminus 进行消息路由 中所述,必须设置每个消息的 properties 部分的 to 字段。允许的 to 地址字符串必须具有相同的格式,即以下之一

  1. /exchanges/:exchange/:routing-key
  2. /exchanges/:exchange
  3. /queues/:queue

其中交换机必须存在。

如果消息无法路由,例如,因为没有队列绑定到目标交换机,RabbitMQ 将使用 released outcome 来处理消息。

如果发布应用程序需要发布(发送)消息到

  • 单个目的地:首选前三种字符串格式之一,而不是第 4 种(null)格式,因为前三种格式提供略微更好的性能
  • 少量不同的目的地:首选为每个目的地打开一个链接,并使用前三种格式之一
  • 大量不同的目的地:首选第 4 种(null)格式,在 to 字段中定义每个目的地

源地址 v2

唯一有效的 v2 源地址字符串格式是

  1. /queues/:queue

客户端从队列 :queue 消费消息。队列必须存在。

百分号编码

地址格式 v2 要求交换机名称、路由键和队列名称根据 RFC 3986 进行百分号编码。

例如,想要发送到交换机 amq.direct,路由键为 my-routing_key/123 的客户端必须使用目标地址 /exchanges/amq.direct/my-routing_key%2F123

请注意,地址格式 v2 中的百分号编码必须应用于所有需要 address 的 AMQP 字段

地址 v1

警告

本节列出了已弃用的 v1 地址字符串格式。

目标地址 v1

  1. /exchange/:exchange/:routing-key
  2. /exchange/:exchange
  3. /topic/:routing-key
  4. /amq/queue/:queue
  5. /queue/:queue
  6. :queue
  7. /queue

第一种格式 /exchange/:exchange/:routing-key 导致给定链接上的所有消息都以路由键 :routing-key 发送到交换机 :exchange。等效的 v2 格式为 /exchanges/:exchange/:routing-key

第二种格式 /exchange/:exchange 导致给定链接上的所有消息都发送到交换机 :exchange,而路由键可以选择在 properties 部分的消息 subject 字段中提供。在 v2 中,为每条消息定义不同的路由键需要将目标地址设置为 AMQP null 值,并将消息 to 字段设置为 /exchanges/:exchange/:routing-key

第三种格式 /topic/:routing-key 导致给定链接上的所有消息都发送到 RabbitMQ 的默认主题交换机 amq.topic,主题为 routing-key。在 v2 中,使用 /exchanges/amq.topic/:routing-key

第四种格式 /amq/queue/:queue 导致给定链接上的所有消息都发送到队列 :queue(更准确地说,在内部,发送到路由键为 :queue 的默认交换机)。队列 :queue 必须存在。在 v2 中,使用 /queues/:queue

第五种格式 /queue/:queue 与第四种格式具有相似的语义。但是,RabbitMQ 将自动声明队列 :queue,即如果队列不存在则创建该队列。队列永远不会被 RabbitMQ 自动删除。在 v2 中,使用 /queues/:queue。RabbitMQ 4.0 允许 AMQP 客户端创建 RabbitMQ 拓扑,包括具有客户端定义的队列类型、属性和参数的队列。因此,RabbitMQ 本身无需为给定的队列目标地址格式自动声明特定队列。

第六种格式 :queue 与第五种格式冗余。

第七种格式导致消息被发送到消息 subject 字段中提供的队列。在 v2 中,要将消息发送到不同的队列,请将目标地址设置为 AMQP null 值,并将消息 to 字段设置为 /queues/:queue

源地址 v1

  1. /exchange/:exchange/:binding-key
  2. /topic/:binding-key
  3. /amq/queue/:queue
  4. /queue/:queue
  5. :queue

第一种格式 /exchange/:exchange/:binding-key 导致 RabbitMQ 声明一个队列,并将该队列绑定到交换机 :exchange,绑定键为 :binding-key。然后从该队列消费消息。

第二种格式 /topic/:binding-key 导致 RabbitMQ 声明一个队列,并将该队列绑定到默认主题交换机 amq.topic,主题过滤器为 :binding-key。然后从该队列消费消息。

第三种格式 /amq/queue/:queue 导致 RabbitMQ 从队列 :queue 消费。队列 :queue 必须存在。

第四种格式 /queue/:queue 导致 RabbitMQ 声明一个队列 :queue 并从该队列消费。

第五种格式 :queue 与第四种格式冗余。

如前所述,RabbitMQ 4.0 允许 AMQP 客户端创建 RabbitMQ 拓扑,包括具有客户端定义的队列类型、属性和参数的队列。因此,RabbitMQ 本身无需为给定的队列源地址格式自动声明特定队列。在 v2 中,客户端应首先声明自己的队列和绑定,然后使用源地址 /queues/:queue 连接,这将导致客户端从该队列消费。

消息注解

当消息传递给消费者时,RabbitMQ 至少设置以下两个消息注解

  • x-exchange 设置为消息最初发布到的交换机
  • x-routing-key 设置为消息最初发布的路由键。

这些消息注解以不同的方式派生,具体取决于消息最初如何发送到 RabbitMQ。例如,它们可以从以下内容派生

  • AMQP 1.0 发布者附加到的 targetaddress 字段。
  • AMQP 1.0 消息 properties 部分的 to 字段。
  • AMQP 0.9.1 basic.publish 帧的 exchangerouting_key 字段,如果消息最初是用 AMQP 0.9.1 发布的。
  • MQTT PUBLISH 数据包的 主题名称,如果消息最初是用 MQTT 发布的。
  • 如果消息最初是用 RabbitMQ 流协议发布的,则为的名称。

但是,AMQP 1.0 客户端不应使用消息注解 x-exchangex-routing-key 向 RabbitMQ 发布消息。RabbitMQ 不会解释它们。相反,如果 AMQP 1.0 客户端想要使用原始路由键重新发布消息到原始交换机,则应相应地设置 address

结果

outcome 表示接收方处理交付(消息)的结果。

下表描述了当客户端为发送者/发布者/生产者,而 RabbitMQ 作为接收者时,outcome 的含义

AMQP 1.0 Outcome等效的 AMQP 0.9.1 帧描述
Acceptedbasic.ack消息路由到的所有队列都已接受该消息。例如,对于仲裁队列,这意味着大多数仲裁队列副本已将消息写入磁盘。因此,发布者可以忘记/删除该消息。
Rejectedbasic.nack消息路由到的至少一个队列拒绝了该消息。当队列长度超过并且队列的 overflow 行为设置为 reject-publish 时,或者当目标经典队列不可用时,会发生这种情况。
RabbitMQ 也会拒绝消息,如 使用 AMQP 匿名 Terminus 进行消息路由 中所述,例如,如果消息的 properties 部分的 to 字段包含无效地址或定义了不存在的交换机。
Releasedbasic.return (后跟 basic.ackbasic.nack)RabbitMQ 无法将消息路由到任何队列。这表明拓扑配置错误,例如当没有匹配的队列绑定到目标交换机时。
Modified目前,RabbitMQ 不会使用 modified outcome 来处理消息。

下表描述了当客户端为接收者/消费者,而 RabbitMQ 作为发送者时,outcome 的含义

AMQP 1.0 Outcome等效的 AMQP 0.9.1 帧描述
Acceptedbasic.ack消费者成功处理了消息。因此,RabbitMQ 可以删除该消息。
Rejectedbasic.nackbasic.rejectrequeue=false消费者指示消息无效且无法处理。RabbitMQ 将死信消息(如果未配置死信,则丢弃消息)。
Releasedbasic.nackbasic.rejectrequeue=true消费者未处理消息。RabbitMQ 重新将消息入队。消息将传递给相同或不同的消费者。
Modified消费者未处理消息,但修改了 消息注解
如果 undeliverable-here=true,RabbitMQ 将死信消息(如果未配置死信,则丢弃消息)。
如果 undeliverable-here=false,RabbitMQ 将重新将消息入队。
有关更多信息,请参见下文

AMQP 1.0 vs. AMQP 0.9.1

顾名思义,AMQP 1.0 是更现代的协议。它是 ISO/IEC 19464OASIS 标准,而 AMQP 0.9.1 不是官方标准。有关协议的更详细比较,请参阅我们的 AMQP 1.0 博客文章

选择正确的协议取决于几个因素,包括

  • 功能需求:是否需要 AMQP 1.0 或 AMQP 0.9.1 的特定功能。
  • 互操作性:如果与其他消息代理的互操作性很重要,请注意,与 AMQP 0.9.1 相比,更多代理支持 AMQP 1.0。
  • 客户端库可用性:是否为您的编程语言提供了受支持的客户端库

AMQP 1.0 功能

本节列出了 RabbitMQ 仅在 AMQP 1.0 中支持的功能,这些功能在 AMQP 0.9.1 中不可用

  • 细粒度流量控制,如博客文章 AMQP 1.0 流量控制的十大优势 中所述
    • 消费客户端应用程序可以动态调整和优先处理它想从特定源队列接收多少消息。
    • 安全有效地使用单个 AMQP 连接进行发布和消费。
    • 当一个目标队列过载时,发布者可以继续高速发送到其他目标队列,而消费者可以继续从同一 AMQP 连接上的其他源队列高速接收。
    • 消费者可以停止或暂停,并在以后恢复。
    • 从一个单活动消费者到下一个的优雅切换,同时保持消息顺序。
    • 源队列可以有效地告知消费者可用消息的大概数量。
  • 队列局部性:RabbitMQ 可以向客户端提供最新的队列拓扑和领导者信息。
    • 例如,RabbitMQ AMQP 1.0 Java 客户端可以通过尝试从托管队列副本的 RabbitMQ 节点“本地”消费,并尝试“本地”发布到托管队列领导者的节点,来利用此信息。
    • 这可以减少集群内流量,从而降低延迟并提高吞吐量。
  • 发送者结算模式 mixed:允许发布者在每条消息的基础上决定是否从代理接收确认
  • Modified Outcome:允许仲裁队列消费者在重新排队或死信消息时添加和修改 消息注解
  • AMQP 过滤器表达式:当通过 AMQP 1.0 从流消费时,RabbitMQ 实现AMQP 过滤器表达式 1.0 版工作草案 09propertiesappliation-properties 过滤器,如 AMQP 1.0 过滤器表达式 博客文章中所述。
    • 也支持字符串前缀和后缀匹配。
    • 此功能允许多个并发客户端各自仅消费消息的子集,同时保持消息顺序。
    • 此功能通过仅分发客户端实际感兴趣的消息来减少 RabbitMQ 和客户端之间的网络流量。
  • 定义明确的 类型
  • 更好定义的 消息头
  • 增强的消息完整性:客户端不仅可以对消息体设置消息哈希、校验和和数字签名,还可以对属性应用程序属性部分进行设置,因为裸消息是不可变的。
  • 流消息保真度:从存储或检索消息时,不会丢失头部的保真度,因为流以 AMQP 1.0 编码格式存储消息。

AMQP 0.9.1 功能

本节列出了 RabbitMQ 仅在 AMQP 0.9.1 中支持的功能,这些功能目前在 AMQP 1.0 中不可用

  • Direct Reply-to:虽然 AMQP 1.0 客户端可以通过声明回复队列来执行远程过程调用 (RPC)(如 RabbitMQ AMQP 1.0 Java 客户端中所述),但 Direct Reply-to 功能仅在 AMQP 0.9.1 中可用。
  • AMQP 0.9.1 信道拦截器:拦截和修改帧的插件,例如 Sharding Plugin目前仅支持 AMQP 0.9.1。
  • 管理 UI 中的消息速率:对于 AMQP 0.9.1 连接,管理 UI 中显示交换机和队列的消息速率。这些速率不适用于 AMQP 1.0 连接。
  • 事务:AMQP 0.9.1 提供有限的支持,而 AMQP 1.0 目前不支持事务(如限制中所列)。

客户端

任何 AMQP 1.0 客户端都应该能够与 RabbitMQ 通信。Broadcom 的 RabbitMQ 团队专门为 RabbitMQ 开发了两个 AMQP 1.0 客户端库

有关更多信息,请参见 AMQP 客户端库页面

目前,AMQP 0.9.1 客户端生态系统更加广泛,Broadcom 的 RabbitMQ 团队支持更多的 AMQP 0.9.1 客户端库

限制

RabbitMQ 不支持以下 AMQP 1.0 功能

Modified Outcome

仲裁队列中支持使用 modified outcome 修改消息注解,但在经典队列中不支持。在中修改消息没有意义,因为流是不可变的日志。

如果字段 undeliverable-here

  • true,经典队列和仲裁队列将死信消息。如果未配置死信,则将丢弃消息。
  • false,经典队列和仲裁队列将重新将消息入队。

AMQP 1.0 Modified Outcome 博客文章描述了用例。

警告

undeliverable-here 的行为可能会在未来的 RabbitMQ 版本中更改。

例如,如果 undeliverable-here = true,则在未来,队列可能会重新将消息入队,同时确保消息不会重新传递到修改链接端点,而不是死信消息。

© . All rights reserved.