理解AMQP,RabbitMQ使用的协议

工程 | Peter Ledbrook | 2010年6月14日 | ...

更新 我修改了第一段,以阐明RabbitMQ和JMS之间的关系。

RabbitMQ是一个轻量级、可靠、可扩展且可移植的消息代理。但与Java开发人员熟悉的许多消息代理不同,它不基于JMS。相反,您的应用程序通过一个平台中立的线级协议与之通信:高级消息队列协议(AMQP)。幸运的是,已经有一个Java客户端库,并且SpringSource正在开发一流的Spring和Grails集成——所以不用担心必须进行低级操作才能使用RabbitMQ。您甚至可以找到公开JMS接口的AMQP客户端库。但是AMQP在操作上与JMS有很大差异,这可能会给习惯了JMS模型的Java开发人员带来麻烦。

为了简化过渡,我将在本文中介绍支撑AMQP的基本概念以及三种常见的用例场景。最后,您将希望对配置RabbitMQ并通过Spring和Grails提供的API使用它有足够的了解。

交换机、队列和绑定

与任何消息系统一样,AMQP是一种消息协议,处理发布者和消费者。发布者生成消息,消费者接收并处理它们。消息代理(如RabbitMQ)的作用是确保发布者的消息到达正确的消费者。为此,代理使用两个关键组件:交换机和队列。下图显示了它们如何将发布者连接到消费者

rabbit-basics

如您所见,设置非常简单。发布者将消息发送到一个命名交换机,消费者从队列中提取消息(或者根据配置,队列将消息推送到消费者)。当然,首先必须建立连接,那么发布者和消费者如何相互发现呢?通过交换机的名称。通常,发布者或消费者创建一个具有给定名称的交换机,然后公开该名称。发布方式取决于具体情况,但可以将其放在公共API文档中或发送给已知的客户端。

消息如何从交换机路由到队列?好问题。首先,队列必须附加到给定的交换机。通常,消费者同时创建队列并将其附加到交换机。其次,交换机接收的消息必须与队列匹配——一个称为“绑定”的过程。

要理解绑定,了解AMQP消息的结构很有用

rabbit-message

消息的头和属性基本上是键值对。它们之间的区别在于,头由AMQP规范定义,而属性可以包含任意特定于应用程序的信息。实际的消息内容只是一系列字节,因此,如果您想在消息中传递文本,则应标准化编码。UTF-8是一个不错的选择。如果需要,您可以在消息头中指定内容类型和编码,但这似乎并不常见。

这与绑定有什么关系?标准头之一称为路由键代理使用它来将消息与队列匹配。每个队列指定一个“绑定键”,如果该键与路由键头的值匹配,则队列接收消息。

交换机类型的概念使事情变得稍微复杂了一些。AMQP规范定义了以下四种类型

交换机类型 行为
直接 绑定键必须与路由键完全匹配——不支持通配符。
主题 与直接相同,但绑定键中允许使用通配符。#匹配零个或多个点分隔的单词,*匹配恰好一个这样的单词。
扇出 路由键和绑定键被忽略——所有发布的消息都发送到所有绑定的队列。

更新 我更正了有关通配符的信息,通配符基于点分隔的单词或术语。

例如,假设发布者将路由键为“NYSE”的消息发送到名为“Stocks”的主题交换机。如果消费者创建一个附加到“Stocks”的队列,其绑定键为#、*或NYSE,则该消费者将收到消息,因为所有三个绑定键都匹配“NYSE”。但是,如果消息发布到直接交换机,则如果绑定键为#或*,则消费者将不会收到消息,因为这些字符被视为文字,而不是通配符。有趣的是,#.#也将匹配NYSE,尽管路由键没有点。

现在考虑一个路由键为“NYSE.TECH.MSFT”的消息。鉴于消息将发送到主题交换机,哪些绑定键将与之匹配?

绑定键 匹配?
NYSE.TECH.MSFT
#
NYSE.#
*.*
NYSE.*
NYSE.TECH.*
NYSE.*.MSFT

这就是全部内容。每个队列支持多个消费者,每个交换机支持多个队列,从而提供了灵活性。实际上,单个队列甚至可以绑定到多个交换机。现在让我们看看其中一些场景。

RPC

AMQP代理可以在客户端和服务之间充当RPC机制。一般设置如下,使用直接交换机

rabbit-rpc

一般顺序如下

  1. 客户端将消息发送到队列,指定:(a)与服务匹配的路由键;以及(b)接收响应的队列的名称。
  2. 交换机将消息传递到服务的队列(在本例中为“ops_q”)。
  3. 队列将消息推送到服务,然后服务执行一些工作并将响应消息发送回交换机,指定与回复队列匹配的routing_key。
  4. 客户端从回复队列中提取响应消息。

从客户端的角度来看,调用可以是阻塞的或非阻塞的。但是,执行哪种操作的难易程度取决于正在使用的客户端库。

RPC场景的关键是确保客户端和服务对初始请求使用相同的交换机,并且客户端知道为路由键指定什么。

至于回复队列,它通常由客户端创建,然后客户端适当地填充reply_to头。此外,虽然您可以使用与请求不同的交换机来回复,但更常见的是对请求和回复都使用相同的交换机。

发布/订阅

JMS具有主题队列的概念,该概念可确保发布者的消息发送到所有订阅者。您可以通过将多个队列绑定到交换机来轻松地在AMQP中实现相同的行为,如下所示

rabbit-pub-sub

更好的是,队列可以通过绑定键过滤它们接收的消息。如果消费者希望接收所有消息,则可以指定绑定键为#——“匹配任意数量的单词”通配符。如前所述,对于普通开发人员来说,*匹配零个或一个(点分隔的)单词,这有点令人困惑。

工作分配

假设您有一个应用程序,它有一堆需要执行的作业。使用AMQP,您可以连接多个消费者,以便每个作业都发送到一个且仅一个消费者。发布者不关心哪个消费者执行工作,只关心工作已完成。这就是工作分配。

配置非常简单,如下图所示

rabbit-work

因此,您有一个绑定到交换机的队列,多个消费者共享该队列。此设置保证只有一个消费者处理给定的消息,无论有多少个消费者。

这些是AMQP代理的三种主要使用模式。虽然我已分别描述了每一种,但将它们组合在一起是相当常见的。例如,在RPC模式中,多个服务可以共享同一个队列(工作分配)。如何配置交换机和队列完全取决于您,现在您应该有足够的了解来确定适合您情况的适当设置。

如果您想进一步了解AMQP,请查看规范本身,尤其是有关通用架构的部分。要开始使用RabbitMQ,只需访问其网站

获取Spring时事通讯

通过Spring时事通讯保持联系

订阅

领先一步

VMware提供培训和认证,以加速您的进步。

了解更多

获取支持

Tanzu Spring在一个简单的订阅中提供OpenJDK™、Spring和Apache Tomcat®的支持和二进制文件。

了解更多

即将举行的活动

查看Spring社区中所有即将举行的活动。

查看全部