原生 AMQP 1.0
我们很高兴地宣布 RabbitMQ 4.0 支持AMQP 1.0 作为核心协议,提供以下优势
- 使 RabbitMQ 现代化,以原生方式支持最新的 AMQP 标准
- 支持更多 AMQP 1.0 功能
- 与 RabbitMQ 3.13 相比,AMQP 1.0 的性能和可扩展性有了显著提升
- 与其他 AMQP 1.0 消息代理的互操作性增强
- RabbitMQ 4.0 中默认启用 AMQP 1.0
AMQP 历史
高级消息队列协议 (AMQP) 是一种应用层协议,也是业务消息传递的标准。
AMQP 最初由摩根大通的 John O’Hara 于 2003 年开发。在他 2007 年的文章迈向商品化企业中间件中,John O’Hara 描述了 AMQP 背后的最初动机。
金融服务行业需要高性能的消息传递中间件(也称为服务总线)。此中间件必须提供持久性以避免消息丢失,并允许使用存储转发和发布订阅技术。用例包括自动化交易和缓冲市场数据事件,这些事件的到达率暂时超过后端服务执行的事务处理率。
一些商业第三方中间件提供商价格过高。有一段时间,华尔街每家大型投资银行都在构建自己的定制消息传递中间件解决方案。但是,他们反复遇到同样的问题。银行不是软件公司,消息传递中间件是复杂的软件,难以正确构建。
银行已经设法合作创建开放的技术标准,例如
- 环球银行金融电讯协会 (SWIFT)。
- 金融信息交换 (FIX) 协议
- FAST 协议(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
客户端将消息发布到交换机,交换机将消息路由到队列。队列存储消息,直到客户端将其消费。
更准确地说,发布者将消息发送到交换机类型的实例。交换机类型定义路由算法。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 客户端应用程序了解服务器拓扑。
RabbitMQ 峰会 2023 演讲使用原生 MQTT 和 MQTT 5.0 为数百万客户端提供服务解释了 AMQ 0.9.1 模型非常强大,可以提供 MQTT 代理所需的大部分功能。RabbitMQ 使用 AMQ 0.9.1 主题交换机类型将传入 MQTT 数据包中的主题与 MQTT 订阅的主题过滤器进行匹配。
AMQP 1.0
AMQP 1.0 比 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)中,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 服务总线 Azure 事件中心 Apache ActiveMQ Apache Qpid Broker-J Apache Qpid C++ 代理 IBM MQ Red Hat AMQ SwiftMQ Solace |
客户端库 | 大量维护良好的客户端库和开发工具 | 生态系统较小,但.NET 和 Java 的客户端库维护良好 |
复杂度 | 中等 | 高 |
模块化架构? | 否 | 是,层级为 1. 类型 2. 传输 3. 消息传递 4. 事务 5. 安全 |
可扩展性 | 尽管服务器模型可以通过交换机类型(以及 RabbitMQ 中的队列类型)进行扩展,并且 RabbitMQ 本身可以通过插件进行扩展,但协议本身的可扩展性非常有限:RabbitMQ 必须定义自定义的 AMQP 0.9.1 协议扩展。 | 为可扩展性而设计 - 分层架构允许将更高层(重新)放置在较低层之上 - 一些帧中的 properties 和capabilities 字段允许扩展- 存在许多 AMQP 1.0 扩展规范。 |
类型系统 | 有限且定义不明确 | 定义明确的类型 |
流量控制 | 简单:例如 消费者预取 | 复杂:链路流量控制和会话流量控制 |
特性 | 定义了最重要的业务消息传递特性 | 与 AMQP 0.9.1 相比,具有更多特性,包括(但不限于) - 暂停消费者 - 传输大型消息 - 流水线连接建立 - 发送者结算模式 mixed - 定义更好的消息头部分,并保持原始消息不变 - 修改后的结果 |
AMQP 0.9.1 的普及
简单地想,人们可能会期望更新的 AMQP 1.0 协议版本更好、功能更丰富、性能更高,因此会使旧的 AMQP 0.9.1 实现过时并被取代。然而,事实并非如此。实际上,仍然在创建新的 AMQP 0.9.1 客户端库,例如彭博社去年开源的C++ 库。令人惊讶的是,即使是全新的 AMQP 0.9.1 代理实现,例如 LavinMQ,也在 AMQP 1.0 发布几年后从头开始开发。
与 AMQP 1.0 相比,AMQP 0.9.1 如此受欢迎的原因是 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。Alvaro Videla 在其 RabbitMQ Summit 2023 主题演讲中展示了另一个互操作性用例,其中消息从 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
自从 AMQP 1.0 于 2011 年发布以来,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 **协议**代理,但继续利用简单、灵活且强大的 AMQ 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 个 Erlang 进程。
因此,原生 AMQP 1.0 遵循了原生 MQTT 的成功案例。
弃用 AMQP 1.0 插件(在图中看起来很简单)实际上需要 12 个月的工程工作。这种大规模的工作是由于以下几个因素造成的
- AMQP 1.0 协议的复杂性:AMQP 1.0 是 RabbitMQ 支持的最复杂的协议,比 AMQP 0.9.1 和 MQTT 都更复杂。
- 队列修改:AMQP 1.0 客户端可以直接从每种队列类型中使用,因此需要对经典队列、仲裁队列和流实现进行更改。
- 滚动升级:我们支持从 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 模型(例如声明和删除交换机、队列和绑定)。此功能利用了AMQP 1.0 上的 HTTP扩展规范。
- 两全其美:应用程序可以通过动态创建服务器拓扑结构来“与中间件保持紧密关系”,同时享受处理复杂 AMQP 1.0 协议的便捷体验。此外,应用程序可以选择绕过轻量级的 RabbitMQ 特定包装器,直接与底层的 AMQP 1.0 客户端库交互,以访问更多高级的 AMQP 1.0 功能。
- 减少网络流量:在某些情况下,它们可以通过识别特定队列所在的 RabbitMQ 节点,从而减少 RabbitMQ 集群内部的流量,允许应用程序从这些节点“本地”发布和消费消息。
- 可选:这些客户端库不是通过 AMQP 1.0 与 RabbitMQ 交互所必需的。任何其他 AMQP 1.0 客户端也应该能够与 RabbitMQ 通信。
RabbitMQ 现代化
RabbitMQ 4.0 完成了其现代化之旅,该之旅始于 2019 年的 RabbitMQ 3.8。这些现代化包括
- 仲裁队列:使用 Raft 共识算法提供安全、复制的队列类型,能够抵御网络分区。
- Prometheus 指标和 Grafana 仪表盘:提供一流的可观测性集成和警报。
- Kubernetes 上的 RabbitMQ:运营商可以在任何地方运行 RabbitMQ。
- 流:一个不可变的日志,使用流协议提供消息重放和高消息吞吐量。
- 经典队列存储版本 2:提供更高的消息吞吐量和更低的内存使用率。
- 商业版灾难恢复解决方案:确保整个数据中心发生故障时业务的连续性。
- 原生 MQTT 和 MQTT 5.0:将 RabbitMQ 转变为物联网代理。
- Khepri:使用 Raft 共识算法提供安全且可扩展的元数据存储,能够抵御网络分区。
- 原生 AMQP 1.0:将 RabbitMQ 的核心协议升级到最新的 AMQP 标准(如本博文中所述)。
我们鼓励您尝试并在 RabbitMQ 4.0 中测试 AMQP 1.0 并提供反馈。您可以使用最新的rabbitmq:4.0-rc
Docker 镜像。虽然我们鼓励您使用 AMQP 1.0 构建新应用程序,但我们将继续在 RabbitMQ 4.x 中支持和维护 AMQP 0.9.1。
敬请关注更多关于 AMQP 1.0 功能和性能基准的技术博文。