更新 我更改了第一段内容,以阐明 RabbitMQ 和 JMS 之间的关系。
RabbitMQ 是一款轻量级、可靠、可扩展且可移植的消息代理。但与 Java 开发人员熟悉的许多消息代理不同,它不基于 JMS。相反,您的应用程序通过平台中立的线级协议(高级消息队列协议 (AMQP))与之通信。幸运的是,已经有一个 Java 客户端库,并且 SpringSource 正在开发一流的 Spring 和 Grails 集成 - 因此,无需担心必须执行低级操作才能使用 RabbitMQ。您甚至可以找到公开 JMS 接口的 AMQP 客户端库。但是 AMQP 在操作上与 JMS 有很大不同,因此可能会给习惯了 JMS 模型的 Java 开发人员带来麻烦。
为了简化过渡,我将在本文中介绍支持 AMQP 的基本概念以及三种常见的使用场景。最后,您希望能够充分了解如何配置 RabbitMQ 并通过 Spring 和 Grails 提供的 API 使用它。
交换机、队列和绑定
与任何消息传递系统一样,AMQP 是一种消息协议,处理发布者和消费者。发布者生成消息,消费者获取并处理它们。消息代理(例如 RabbitMQ)的工作是确保发布者的消息传递到正确的消费者。为了做到这一点,代理使用两个关键组件:交换机和队列。下图显示了它们如何将发布者连接到消费者
如您所见,设置非常简单。发布者将消息发送到命名交换机,消费者从队列中提取消息(或者根据配置,队列将消息推送到消费者)。当然,首先必须建立连接,那么发布者和消费者如何发现彼此呢?通过交换机的名称。通常,发布者或消费者使用给定名称创建交换机,然后公开该名称。发布方式取决于具体情况,但可能会将其放在公共 API 文档中或发送给已知的客户端。
消息如何从交换机路由到队列?好问题。首先,队列必须附加到给定的交换机。通常,消费者会创建队列并将其附加到交换机。其次,交换机接收的消息必须与队列匹配 - 这个过程称为“绑定”。
要了解绑定,了解 AMQP 消息的结构很有用
消息的标头和属性基本上是键值对。它们之间的区别在于,标头由 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 机制。一般设置如下,使用直接交换机
一般序列如下
- 客户端将消息发送到队列,指定:(a) 与服务匹配的路由键;以及 (b) 从中提取响应的队列名称。
- 交换机将消息传递到服务的队列(在本例中为“ops_q”)。
- 队列将消息推送到服务,然后服务执行一些工作并将响应消息发送回交换机,指定与回复队列匹配的 routing_key。
- 客户端从回复队列中提取响应消息。
从客户端的角度来看,调用可以是阻塞的或非阻塞的。但是,执行哪种操作的难易程度取决于使用的客户端库。
RPC 场景的关键是确保客户端和服务对初始请求使用相同的交换机,并且客户端知道为路由键指定什么。
至于回复队列,它通常由客户端创建,然后客户端适当地填充reply_to标头。此外,尽管您可以使用与请求不同的交换机进行回复,但更常见的是对请求和回复都使用相同的交换机。
发布/订阅
JMS 具有主题队列的概念,以确保发布者的消息传递到所有订阅者。您可以通过如下方式将多个队列绑定到交换机,轻松地在 AMQP 中实现相同的功能
更好的是,队列可以通过绑定键过滤它们接收的消息。如果消费者想要接收所有消息,则可以指定“#”绑定键 - “匹配任意数量的单词”通配符。正如前面提到的,令人困惑的是,“*”匹配零个或一个(点分隔的)单词。
工作分配
假设您有一个应用程序,其中包含许多需要执行的作业。使用 AMQP,您可以连接多个消费者,以便每个作业只传递到其中一个消费者。发布者不关心哪个消费者执行工作,只关心工作是否完成。这是工作分配。
配置非常简单,如下图所示
因此,您有一个绑定到交换机的队列,多个消费者共享该队列。此设置保证只有一个消费者处理给定的消息,无论有多少消费者。
这些是 AMQP 代理的三种主要使用模式。虽然我已经分别描述了每一种,但通常将它们组合在一起。例如,在 RPC 模式中,多个服务可以共享同一个队列(工作分配)。如何配置交换机和队列完全取决于您,现在您应该能够充分了解如何为您的情况确定合适的设置。
如果您想进一步了解 AMQP,请查看 规范本身,尤其是关于通用架构的部分。要开始使用 RabbitMQ,只需访问 其网站。