Apache ActiveMQ Artemis 是一个异步消息传递系统,是 面向消息的中间件 的示例,在本书的剩余部分中,我们将简称为消息传递系统。
我们首先将简要概述消息传递系统能做什么,它们在什么地方有用以及您将在消息传递领域中听到的各种概念。
如果您已经熟悉消息传递系统是什么以及它的功能,那么您可以跳过本章。
1. 一般概念
消息传递系统允许您将异构系统松散地耦合在一起,同时通常提供可靠性、事务和其他许多功能。
与基于 远程过程调用 (RPC) 模式的系统不同,消息传递系统主要使用异步消息传递模式,请求和响应之间没有紧密的关系。大多数消息传递系统也支持请求-响应模式,但这并不是消息传递系统的首要功能。
将系统设计为端到端的异步,可以让您真正利用硬件资源,最大程度地减少线程阻塞在 IO 操作上的时间,并将网络带宽利用到极致。使用 RPC 方法,您必须等待每个请求的响应,因此受到网络往返时间或网络 *延迟* 的限制。在异步系统中,您可以对不同方向的消息流进行流水线处理,因此受到网络 *带宽* 而不是延迟的限制。这通常允许您创建性能更高的应用程序。
消息传递系统将消息的发送者与消息的消费者解耦。消息的发送者和消费者是完全独立的,彼此一无所知。这允许您创建灵活、松散耦合的系统。
通常,大型企业使用消息传递系统来实现消息总线,该总线将异构系统松散地耦合在一起。消息总线通常构成 企业服务总线 (ESB) 的核心。使用消息总线来解耦不同的系统可以让系统更容易地增长和适应。它还允许更灵活地添加新系统或淘汰旧系统,因为它们之间没有脆弱的依赖关系。
2. 消息传递风格
2.1. 点对点
使用这种类型的消息传递,您将消息发送到队列。然后,消息通常会持久化以提供传递保证,然后一段时间后,消息传递系统将消息传递给消费者。消费者随后处理消息,完成后,它确认消息。消息被确认后,它会从队列中消失,不再可用。如果系统在消息服务器收到消费者的确认之前崩溃,那么在恢复后,消息将再次可用以传递给消费者。
在点对点消息传递中,队列上可以有多个消费者,但特定消息最多只能被其中一个消费者消费。队列的发送者(也称为 *生产者*)与队列的接收者(也称为 *消费者*)完全解耦 - 它们不知道彼此的存在。
点对点消息传递的一个典型例子是公司图书订购系统中的订单队列。每个订单都表示为一条消息,该消息被发送到订单队列。让我们假设有很多前端订购系统将订单发送到订单队列。当一条消息到达队列时,它会持久化 - 这确保了如果服务器崩溃,订单不会丢失。让我们还假设订单队列上有许多消费者 - 每个消费者都代表一个订单处理组件的实例 - 这些消费者可以位于不同的物理机器上,但从同一个队列消费。消息传递系统将每条消息传递给订单处理组件中的一个且仅一个。不同的消息可以被不同的订单处理器处理,但单个订单只能被一个订单处理器处理 - 这确保了订单不会被处理两次。
当订单处理器收到一条消息时,它会执行订单,将订单信息发送到仓库系统,然后使用订单详细信息更新订单数据库。完成这些操作后,它会确认消息,告诉服务器订单已处理,可以忘记了。通常,发送到仓库系统的操作、数据库中的更新和确认将在单个事务中完成,以确保 ACID 属性。
2.2. 发布订阅
在发布订阅消息传递中,许多发送者可以将消息发送到服务器上的一个实体,通常称为 *主题*(例如,在 JMS 世界中)。
主题上可以有多个 *订阅*,订阅只是主题消费者的另一种说法。每个订阅都会收到发送到主题的 *每个* 消息的 *副本*。这与消息队列模式不同,在消息队列模式中,每条消息只会被一个消费者消费。
订阅可以选择是 *持久* 的,这意味着它们会保留发送到主题的每条消息的副本,直到订阅者消费它们 - 即使服务器在期间崩溃或重新启动。非持久订阅只持续到创建它们的连接的寿命。
发布订阅消息传递的一个例子是新闻提要。当世界各地的不同编辑创建新闻文章时,它们会被发送到新闻提要主题。世界上有许多订阅者有兴趣接收新闻项目 - 他们每个人都会创建一个订阅,消息传递系统会确保将每条新闻消息的副本传递给每个订阅。
3. 传递保证
大多数消息传递系统的一个关键功能是 *可靠消息传递*。在可靠消息传递中,服务器会保证消息将被传递给队列的每个消费者或主题的每个持久订阅一次且仅一次,即使在系统故障的情况下也是如此。这对许多企业来说至关重要;例如,您不希望订单执行多次,也不希望任何订单丢失。
在其他情况下,您可能不关心一次且仅一次传递保证,并且乐于处理重复传递或丢失的消息 - 这方面的例子可能是短暂的股票价格更新 - 这些更新会很快被同一股票的下一个更新所取代。消息传递系统允许您配置所需的传递保证。
4. 事务
消息传递系统通常支持在一个本地事务中发送和确认多条消息。Apache ActiveMQ Artemis 还支持将消息发送和确认作为大型全局事务的一部分 - 使用 XA 的 Java 映射:JTA。
5. 持久性
消息要么是持久性的,要么是非持久性的。持久性消息将被持久化到永久存储中,并且能够在服务器故障或重启后存活。非持久性消息无法在服务器故障或重启后存活。持久性消息的例子可能是订单或交易,因为它们不能丢失。非持久性消息的例子可能是短暂的股票价格更新,不需要在重启后存活。
6. 消息传递 API
客户端应用程序如何与消息传递系统交互以发送和消费消息?
一些消息传递系统提供自己的专有 API,客户端通过该 API 与消息传递系统通信。
在该领域中,还有一些与消息传递系统进行操作的标准方法以及一些新兴标准。让我们简要看一下这些标准。
6.1. JMS & Jakarta 消息传递
JMS 历史上是 Oracle Java EE 规范的一部分。但是,在 2017 年,控制权转移到了 Eclipse 基金会,现在它被称为 Jakarta 消息传递,它是 Jakarta EE 的一部分。
这是一个 Java API,它封装了消息队列和发布订阅消息传递模式。它是一个最低公分母规范 - 也就是说,它是为了封装当时已存在的消息传递系统的通用功能而创建的。
这是一个非常流行的 API,由大多数消息传递系统实现。它只对运行 Java 的客户端可用。
它没有定义标准的线格式 - 它只定义了一个编程 API,因此来自不同供应商的客户端和服务器无法直接互操作,因为每个服务器都会使用供应商自己的内部线协议。
Apache ActiveMQ Artemis 提供了客户端实现,这些实现完全符合 JMS 1.1 & 2.0 以及 Jakarta 消息传递 2.0 & 3.0。
6.2. 系统特定 API
许多系统提供自己的编程 API,用于与消息传递系统交互。这样做的好处是,它允许将所有系统功能暴露给客户端应用程序。像 JMS 这样的 API 通常不够丰富,无法暴露大多数消息传递系统提供的额外功能。
Apache ActiveMQ Artemis 为客户端提供了自己的核心客户端 API,如果他们希望访问超出 JMS API 可访问范围的功能,可以使用该 API。
请参阅 核心,了解如何将核心 API 与 Apache ActiveMQ Artemis 配合使用。
7. 高可用性
高可用性 (HA) 意味着系统应该在出现一台或多台服务器故障后仍然保持运行。对 HA 的支持程度因各种消息传递系统而异。
Apache ActiveMQ Artemis 提供自动故障转移,您的会话会在服务器发生故障时自动重新连接到备份服务器。
有关 HA 的更多信息,请参阅 高可用性和故障转移。
8. 集群
许多消息传递系统允许您创建称为 *集群* 的消息传递服务器组。集群允许将发送和消费消息的负载分散到多个服务器上。这允许您的系统通过向集群添加新的服务器来进行水平扩展。
对集群的支持程度因消息传递系统而异,有些系统的集群相当基础,集群成员之间几乎没有意识。
Apache ActiveMQ Artemis 提供了非常可配置的最新集群模型,根据每个节点上的消费者数量以及它们是否准备好接收消息,可以智能地在集群中的服务器之间负载均衡消息。
Apache ActiveMQ Artemis 还具有在集群节点之间自动重新分配消息的能力,以防止任何特定节点出现消息饥饿。
有关集群的完整详细信息,请参见集群。
9. 桥接和路由
一些消息系统允许将孤立的集群或单个节点桥接在一起,通常通过不可靠的连接(如广域网 (WAN) 或互联网)进行桥接。
桥接通常从一台服务器上的队列中消费消息,并将消息转发到另一台服务器上的另一个队列。桥接可以应对不可靠的连接,在连接恢复可用时自动重新连接。
Apache ActiveMQ Artemis 桥接可以配置过滤器表达式,只转发某些消息,还可以挂钩转换。
Apache ActiveMQ Artemis 还允许在服务器端配置中配置队列之间的路由。这允许设置复杂的路由网络,将消息从一个目的地转发或复制到另一个目的地,形成一个互连代理的全球网络。