原生 AMQP 1.0
我们很高兴地宣布,RabbitMQ 4.0 将 AMQP 1.0 作为核心协议提供支持,带来了以下优势:
- 现代化 RabbitMQ,原生支持最新的 AMQP 标准
- 支持更多 AMQP 1.0 功能
- 与 RabbitMQ 3.13 相比,AMQP 1.0 的性能和可扩展性显著提升
- 与其他 AMQP 1.0 消息中间件的互操作性更强
- AMQP 1.0 在 RabbitMQ 4.0 中默认启用
AMQP 历史
高级消息队列协议 (AMQP) 是一种应用层协议,也是业务消息传递的标准。
AMQP 最初由摩根大通 (JPMorgan) 的 John O’Hara 于 2003 年开发。在 2007 年发表的题为《迈向商品化企业中间件》(Toward a Commodity Enterprise Middleware) 的文章中,John O’Hara 描述了 AMQP 背后的最初动机。
金融服务行业需要一种高性能的消息中间件(也称为服务总线)。该中间件必须提供持久性以避免消息丢失,并支持“存储-转发”和“发布-订阅”技术。使用场景包括自动化交易以及市场数据事件的缓冲,以应对到达速率暂时超过后端服务处理速率的情况。
一些商业化的第三方中间件供应商价格过于昂贵。曾几何时,华尔街的每一家大型投资银行都在构建自己的定制消息中间件解决方案。然而,他们反复遇到同样的问题。银行并非软件公司,而消息中间件是复杂的软件,很难做到尽善尽美。
银行设法在创建开放技术标准方面进行了合作,例如:
- 环球银行金融电信协会 (SWIFT)。
- 金融信息交换 (FIX) 协议
- FAST 协议 (FIX Adapted for STreaming,针对流媒体适配的 FIX)
- 金融产品标记语言 (FpML)
因此,这些组织也应该有能力为业务消息传递创建一个开放标准:这就是 AMQP 诞生的方式。
AMQP 规范的要求如下:
- 开放标准
- 无专利限制,使任何人都能进行兼容性实现
- 对商业实现具有吸引力(否则 AMQP 规范将无法成功)
- 应该有不止一种实现(毕竟要符合标准的定义)
- AMQP 软件必须在实时系统中经过验证。中间件是任何系统的关键组成部分,必须值得信赖。这种信任必须通过实际表现来赢得。
- 由多家独立公司共同努力,解决连接系统的相同难题
快进到今天,AMQP 已被全球大多数大型企业跨行业用于关键的消息传递基础设施中,而 RabbitMQ 是最流行的开源 AMQP 消息代理。
AMQP 版本
下表显示了不同 AMQP 规范的发布时间
| AMQP 版本 | 发布日期 |
|---|---|
| 0.8 | 2006 年 6 月 |
| 0.9 | 2006 年 12 月 |
| 0.10 | 2008 年 2 月 |
| 0.9.1 | 2008 年 11 月 |
| 1.0 | 2011 年 10 月 |
在 2007 年的文章中,John O'Hara 写道:
AMQP 工作组正在迅速完善该协议,并希望在 2008 年期间达到 1.0 版本。
1.0 版本的发布不仅比预期晚了三年,而且协议规范也发生了彻底的变化。结果是,AMQP 1.0 与 AMQP 0.9.1 等预发布版本相比,完全是两种不同的协议。
当在对话或文档中提到“AMQP”时,通常会省略版本号,从而导致对于具体指的是哪个协议产生了很多困惑。由于 RabbitMQ 是最流行的消息代理,许多网站指的是 AMQP 0.9.1。而其他文档反过来又指的是 AMQP 1.0。
本博客文章的其余部分将忽略 AMQP 0.8、0.9 和 0.10 版本,因为它们是早已不再使用的旧规范。相反,我们将重点放在 AMQP 0.9.1 和 1.0 版本之间的差异上,这两个版本在当今的消息代理中都被大量使用。
从宏观角度来看,AMQP 0.9.1 和 AMQP 1.0 之间最大的区别在于:
- AMQP 0.9.1 定义了客户端与服务器之间的协议,以及诸如交换机 (exchanges)、队列 (queues) 和绑定 (bindings) 等服务器实体。
- AMQP 1.0 仅定义了客户端与服务器之间的协议。

AMQP 0.9.1
客户端将消息发布到交换机,交换机将消息路由到队列。队列存储消息,直到被客户端消费。
更准确地说,发布者将消息发送到某个交换机类型的实例。交换机类型定义了路由算法。AMQP 0.9.1 规范定义了不同的交换机类型,必须由 AMQP 0.9.1 代理实现
交换机还提供了一个扩展点。RabbitMQ 提供了多种其他交换机类型,第三方插件也可以轻松地添加到 RabbitMQ 中。
根据从队列到交换机实例的绑定(包括绑定键)以及消息的路由键(以及可能的其他头部信息),交换机类型算法决定将消息复制到哪些队列。
因此,AMQP 0.9.1 中的模型既简单又灵活且强大。如果需要,可以创建复杂的路由拓扑,包括交换机到交换机的绑定。
交换机、队列和绑定可以由管理员预先声明,也可以通过 HTTP 动态创建,或者更常见的是,由客户端应用程序直接通过 AMQP 0.9.1 创建。具体来说,AMQP 0.9.1 定义了诸如 exchange.declare、queue.declare 和 queue.bind 等协议帧。因此,AMQP 0.9.1 客户端应用程序感知服务器拓扑。
2023 年 RabbitMQ 峰会的演讲《使用原生 MQTT 和 MQTT 5.0 为数百万客户端提供服务》解释说,AMQP 0.9.1 模型非常强大,它提供了 MQTT 代理所需的大部分功能。RabbitMQ 使用 AMQP 0.9.1 主题交换机类型,将传入 MQTT 数据包中的主题与 MQTT 订阅的主题过滤器进行匹配。
AMQP 1.0
AMQP 1.0 比 AMQP 0.9.1 更通用。AMQP 1.0 没有定义服务器模型。事实上,AMQP 1.0 非常通用,甚至不需要存在中央代理。AMQP 1.0 定义了对等方之间互相交换消息。它们通过向目标 (target) 发送消息以及从源 (source) 消费消息来实现。
目标和源都包含一个地址 (address)。AMQP 1.0 地址指向什么内部对象以及如何解析地址,这在 AMQP 1.0 规范中并未定义,因为不同的 AMQP 1.0 代理具有不同的接收、存储和发送消息的模型。
例如,在实现 AMQP 0.9.1 模型的 AMQP 1.0 代理中(如 RabbitMQ),AMQP 1.0 目标地址指向一个 AMQP 0.9.1 交换机,而 AMQP 1.0 源地址指向一个 AMQP 0.9.1 队列。其他 AMQP 1.0 代理可能会选择让地址指向不可变日志(流)、主题、某种内存数据结构或 SQL 数据库。而另一个 AMQP 1.0 实现可能只是一个客户端库,直接将消息发送给另一个客户端,而无需任何中央代理参与,在这种情况下,地址可能指向某个操作系统套接字。由 AMQP 1.0 实现来决定它如何解析地址以及如何存储消息。
由于 AMQP 1.0 规范非常通用,使得各种各样的代理更容易添加对 AMQP 1.0 的支持,而不受其存储和转发消息所使用的模型的限制。这就是为什么与 AMQP 0.9.1 代理相比,存在更多的 AMQP 1.0 代理。
AMQP 0.9.1 与 AMQP 1.0
下表对 AMQP 0.9.1 和 AMQP 1.0 进行了比较
| AMQP 0.9.1 | AMQP 1.0 | |
|---|---|---|
| 是否定义了服务器模型? | 是:交换机、队列、绑定 | 否:由实现决定服务器模型 |
| 标准 | - | ISO/IEC 19464 OASIS |
| 代理 | RabbitMQ SwiftMQ LavinMQ Apache Qpid Broker-J | RabbitMQ Azure Service Bus Azure Event Hubs Azure IoT Hub Apache ActiveMQ Apache Artemis Apache Qpid Broker-J Apache Qpid C++ Broker IBM MQ Red Hat AMQ SwiftMQ Solace |
| 客户端库 | 大量维护良好的客户端库和开发人员工具 | 生态系统较小,但针对 .NET 和 Java 有维护良好的客户端库 |
| 复杂度 | 中等 | 高 |
| 模块化架构? | 否 | 是,层级包括 1. 类型 (Types) 2. 传输 (Transport) 3. 消息传递 (Messaging) 4. 事务 (Transactions) 5. 安全性 (Security) |
| 可扩展性 | 虽然服务器模型可以通过交换机类型(以及 RabbitMQ 中的队列类型)进行扩展,并且 RabbitMQ 本身可以通过插件进行扩展,但协议本身的可扩展性非常有限:RabbitMQ 不得不定义自定义的 AMQP 0.9.1 协议扩展。 | 专为可扩展性设计 - 分层架构允许在底层之上(替)换高层 - 某些帧中的 properties 和 capabilities 字段允许扩展- 存在大量的 AMQP 1.0 扩展规范。 |
| 类型系统 | 有限且定义不佳 | 定义良好的类型 |
| 流控制 | 简单:例如消费者预取 | 复杂:链路流控和会话流控 |
| 特性 | 定义了最重要的业务消息传递功能 | 与 AMQP 0.9.1 相比具有更多功能,包括(但不限于): - 修改结果 (modified outcome) - 暂停消费者 - 传输大消息 - 流水线式连接建立 - 发送者结算模式 (sender settle mode) mixed- 定义更佳的消息头部部分,具有原始消息的不可变性 |
AMQP 0.9.1 的普及性
天真地想,人们可能会认为较新的 AMQP 1.0 协议版本更好、功能更丰富、性能更高,因此会淘汰并取代旧的 AMQP 0.9.1 实现。然而,事实并非如此。实际上,新的 AMQP 0.9.1 客户端库仍在创建中,例如彭博社 (Bloomberg) 去年开源的 C++ 库。令人惊讶的是,即使在 AMQP 1.0 发布多年后,甚至还有像 LavinMQ 这样全新的 AMQP 0.9.1 代理实现是从零开始开发的。
AMQP 0.9.1 比 AMQP 1.0 如此受欢迎的原因是 RabbitMQ 强大的生态系统和社区,以及 AMQP 0.9.1 复杂度较低的事实。简单性通常会胜出,因为简单性意味着开发人员和用户能够理解该技术,这反过来又导致开发出更多的客户端库并获得更高的采用率。
如前所述,AMQP 0.9.1 客户端应用程序感知交换机、队列和绑定。John O’Hara 甚至在 2007 年的文章中指出,如果不定义包含模型(交换机、队列和绑定)的 AMQP 0.9.1 协议,就无法实现互操作性:
AMQP [0.9.1] 分为两个主要领域:传输模型和排队模型。AMQP [0.9.1] 的独特之处在于它详尽地指定了其在排队模型内提供的服务的语义;由于应用程序与其中间件有着非常密切的关系,因此这需要得到明确定义,否则无法实现互操作性。
十七年后,我们可以断定他是对的。
鉴于 2024 年 AMQP 0.9.1 的普及程度仍然高于 AMQP 1.0,AMQP 1.0 是否失败了?如上表所示,许多代理已变得兼容 AMQP 1.0。虽然没有单一的代理能够实现整个 AMQP 1.0 规范(由于其复杂性),但任何 AMQP 1.0 客户端都可以与这些兼容 AMQP 1.0 的代理交换消息。因此,可以说,我们得出结论:AMQP 0.9.1 和 AMQP 1.0 都成功了。
为什么 RabbitMQ 4.0 会获得 AMQP 1.0 升级?
我们投资支持一流 AMQP 1.0 的原因有几个:
- 客户需求:商业客户和开源用户都要求提供更好的 AMQP 1.0 支持。虽然这不是我们投资的主要原因,但有时对话处于如此高级、非技术的层面,以至于潜在客户更愿意将他们的核心消息传递基础设施基于最新的 AMQP 标准,而不是预发布的 AMQP 规范。一个例子可以在这里找到。
- 协议功能:如上表部分所示,AMQP 1.0 规范拥有定义更佳的类型系统和更多的协议功能。本博文仅概述了 AMQP 0.9.1 与 AMQP 1.0,后续文章将更详细地介绍 AMQP 1.0 功能。
- 可扩展性:AMQP 1.0 专为可扩展性而设计。协议规范中投入了更多的思考,我们相信可以在未来的 RabbitMQ 版本中利用这种可扩展性。例如,得益于这种可扩展性,RabbitMQ 可以将队列位置信息告知 AMQP 1.0 客户端,允许客户端发布和消费本地连接到的 RabbitMQ 节点。
- 性能改进:旧的 RabbitMQ 3.13 插件功能有限,设计欠佳,并且由于通过 AMQP 0.9.1 协议进行内部代理,速度较慢。RabbitMQ 4.0 中修复了许多 AMQP 1.0 实现错误。
- 互操作性:像 RabbitMQ 这样的开源消息代理的核心在于互操作性。AMQP 消息应该能够在不同的代理和组织之间传输。由于许多代理实现了 AMQP 1.0,用户可以更容易地迁移到 RabbitMQ(或从 RabbitMQ 迁移)。Alvaro Videla 在 2023 年 RabbitMQ 峰会的主题演讲中展示了另一个互操作性用例,其中消息从 RabbitMQ 移动到 Microsoft Fabric 中的实时智能,以使用各种 Azure 云服务分析应用程序消息。
- 多协议消息代理:RabbitMQ 是市场上最好的多协议消息代理。它原生支持 AMQP 0.9.1、MQTT、Streams,以及自 RabbitMQ 4.0 以来的 AMQP 1.0。STOMP 通过插件支持。RabbitMQ 为用户提供了如何发布和消费消息的完全灵活性:可以使用不同的协议发布和消费同一个队列中的消息。RabbitMQ 通过执行文档记录完善的消息协议转换而脱颖而出。原生支持 AMQP 1.0 为用户提供了更大的灵活性。
RabbitMQ 3.13 中的 AMQP 1.0
自 2011 年 AMQP 1.0 发布以来,RabbitMQ 一直通过插件提供对 AMQP 1.0 的有限支持。

RabbitMQ 3.13 及之前的 AMQP 1.0 插件在内部通过 AMQP 0.9.1 代理 AMQP 1.0。换句话说,该插件将从客户端接收到的每个 AMQP 1.0 消息转换为 AMQP 0.9.1 消息,然后通过 AMQP 0.9.1 协议将此转换后的消息发送到 RabbitMQ 核心。这种方法有重大缺点:
- 功能支持有限:对 AMQP 1.0 的支持仅限于 AMQP 0.9.1 协议提供的功能子集。
- 性能缓慢:每个消息都必须在 AMQP 0.9.1 和 AMQP 1.0 之间进行转换。
- 资源占用大:这种方法在内存和 CPU 使用方面资源密集,因为插件中的每个 AMQP 1.0 会话都包含一个 AMQP 0.9.1 客户端并维护 AMQP 0.9.1 状态。
正如《使用原生 MQTT 为数百万客户端提供服务》博文中所述,MQTT 插件在 RabbitMQ 3.11 之前在概念上以相同的方式工作:它也通过 AMQP 0.9.1 协议进行内部代理。
RabbitMQ 4.0 中的 AMQP 1.0
从 RabbitMQ 4.0 开始,原生 AMQP 1.0 支持取代了 AMQP 1.0 插件。

AMQP 1.0 客户端直接向交换机(AMQP 1.0 目标)发送消息,并直接从队列(AMQP 1.0 源)接收消息。换句话说,原生 AMQP 1.0 不再通过 AMQP 0.9.1 协议进行代理,而是继续利用简单、灵活且强大的 AMQP 0.9.1 模型。这种转变带来了几个好处:
- 功能支持增强:支持更多的 AMQP 1.0 功能。这反映了 RabbitMQ 3.12 中引入原生 MQTT 如何促进了更多协议功能的添加,例如 RabbitMQ 3.13 中的 MQTT 5.0。
- 性能快速:原生 AMQP 1.0 提供更好的吞吐量和更低的延迟。
- 资源消耗轻:代理上的内存和 CPU 使用率更低,每个 AMQP 1.0 会话使用一个 Erlang 进程,而 RabbitMQ 3.13 中则为 15 个。
因此,原生 AMQP 1.0 延续了原生 MQTT 的成功故事。
淘汰 AMQP 1.0 插件(图表中看起来很简单)实际上需要 12 个月的工程工作。这种巨大的努力归因于几个因素:
- AMQP 1.0 协议的复杂性:AMQP 1.0 是 RabbitMQ 支持的最复杂的协议,比 AMQP 0.9.1 和 MQTT 都要复杂。
- 队列修改:AMQP 1.0 客户端可以直接从每种队列类型中消费,这需要对经典队列、法定队列 (quorum queues) 和流实现进行更改。
- 滚动升级:我们支持从 RabbitMQ 3.13 滚动升级到 4.0,允许您在不中断服务的情况下升级 AMQP 1.0 工作负载。
尽管 RabbitMQ 4.0 原生支持 AMQP 1.0,但这并不意味着 RabbitMQ 支持所有 AMQP 1.0 功能。与其他任何 AMQP 1.0 代理一样,RabbitMQ 的 AMQP 1.0 实现也有文档记录的限制。
RabbitMQ AMQP 1.0 客户端
我们专门为 RabbitMQ 开发了两个新的 AMQP 1.0 客户端库。
这些客户端库具有以下特性:
- 轻量级封装:它们是基于现有的开源 AMQP 1.0 客户端库构建的,包含 RabbitMQ 特定逻辑的轻量级封装。
- 主观 API:它们提供了一个简单且安全的 API,旨在帮助应用程序开发人员轻松上手通过 AMQP 1.0 发送和接收消息。
- RabbitMQ 模型集成:它们使应用程序能够通过 AMQP 1.0 管理 RabbitMQ 的 AMQ 0.9.1 模型(如声明和删除交换机、队列和绑定)。此功能利用了HTTP over AMQP 1.0 扩展规范。
- 两全其美:应用程序可以通过动态创建服务器拓扑来保持与中间件的“密切关系”,同时在复杂的 AMQP 1.0 协议中享受直接的体验。此外,应用程序还可以选择绕过特定的轻量级封装,直接与底层的 AMQP 1.0 客户端库交互,以访问更高级的 AMQP 1.0 功能。
- 减少网络流量:在某些场景下,它们可以通过识别给定队列所在的 RabbitMQ 节点来减少 RabbitMQ 集群内的流量,允许应用程序从这些节点“本地”发布和消费。
- 可选:通过 AMQP 1.0 与 RabbitMQ 交互不需要这些客户端库。任何其他 AMQP 1.0 客户端也应该能够与 RabbitMQ 通信。
RabbitMQ 现代化
RabbitMQ 4.0 完成了其现代化之旅,该之旅始于 2019 年的 RabbitMQ 3.8。这些现代化包括:
- 法定队列 (Quorum Queues):使用 Raft 共识算法提供一种安全、复制的队列类型,能够抵抗网络分区。
- Prometheus 指标和 Grafana 面板:提供一流的可观测性集成和警报。
- Kubernetes 上的 RabbitMQ:在任何地方运行 RabbitMQ 的操作员。
- 流 (Streams):一种不可变日志,提供消息重放和高消息吞吐量,使用流协议。
- 经典队列存储版本 2:提供更高的消息吞吐量和更低的内存使用率。
- 商业灾难恢复解决方案:确保整个数据中心宕机时的业务连续性。
- 原生 MQTT 和 MQTT 5.0:将 RabbitMQ 转变为物联网代理。
- Khepri:使用 Raft 共识算法提供安全且可扩展的元数据存储,能够抵抗网络分区。
- 原生 AMQP 1.0:将 RabbitMQ 的核心协议升级到最新的 AMQP 标准(如本博文所述)。
我们鼓励您在 RabbitMQ 4.0 中尝试和测试 AMQP 1.0,并提供反馈。您可以使用最新的 rabbitmq:4.0 docker 镜像。虽然我们鼓励您使用 AMQP 1.0 构建新应用程序,但我们将继续在 RabbitMQ 4.x 中支持和维护 AMQP 0.9.1。
观看我们的 2024 年 RabbitMQ 峰会关于原生 AMQP 1.0 的演讲,并阅读更多关于 AMQP 1.0 功能和性能基准测试的技术博文。
