Chapter 4. 消息的相关概念

HornetQ是一个异步的 面向消息的中间件。在本文档中我们简称为消息系统。

首先我们简要介绍消息系统是做什么的,在哪些领域得到应用,以及与消息相关的一些概念。

如果你已经对消息系统的这些方面的知识很熟悉,可以跳过本章内容。

4.1. 消息相关的概念

消息系统可以将不同异种的系统松散地耦合在一起,提供基本的可靠性,事务及其它功能的支持。

与基于远程过程调用 (RPC) 的系统不同,消息系统主要采用异步传送的方式,请求与响应之间的耦合很松。 大多数的消息系统也支持请求-响应的方式,但这不是消息的主要功能。

端与端之间采用异步通信的好处是可以充分利用硬件资源,最大程度减少IO操作引起的线程阻塞,并充分利用网络带宽。 而采用RPC方式,每一个请求必须要等待响应返回才能继续,因而要依赖你的网络的速度 (latency)。异步系统则能将消息以管道的方式传送, 它只受带宽的限制,并不因网络速度而降低效率。利用异步的方式往往可以创建更高效率的应用。

消息系统将消息的发送方与接收方分开,使消息的发送所接收完全独立于对方,有利于创建灵活的、松耦的系统。

大型的企业应用通常采用消息系统来实现一种消息总线,并基于这个总线将企业的各种不同结构的系统松散地连在一起工作。 消息总线也常常是企业服务总线(ESB)的核心。 采用这种方式搭建的松耦合系统可以非常容易地扩展和修改。由于系统各模块之间的信赖关系很弱,所以在需要时可以对系统灵活地添加和减少模块。

4.2. 消息的种类

消息系统通常支持两种异步的传送模式:消息队列 (又称为点对点消息传送)模式和广播/订阅模式

4.2.1. 消息队列模式

在这种模式中消息被发送到队列中。通常消息会被持久化以保证可靠的传送。消息系统会将队列中的消息传送给接收者 (receiver或consumer)。当接收者处理消息完成后,它会发出完成的通知给消息系统。得到通知的消息就会从队列 中删除,因此该消息不会被再次传送。如果在收到消息前消息服务器发生故障导致系统崩溃,当系统恢复时, 该消息会被再次传送给接收者。

这种模式允许一个队列有多个接收者。但是一个消息最多只传送给一个接收者。一个队列的消息发送者(sender或producer) 与接收者是完全独立的。它们不知道彼此的存在。

图书订单系统是一个典型的消息队列的用例。每一个订单都被包装为一个消息传送到订单队列中。假定有多个图书订购的终 端向订单队列发关订单消息。当一个消息到达队列时它被持久化以防止系统崩溃时订单的丢失。再假定有多个订单处理中心 分布在不同的机器上接收这个订单队列的消息。消息系统将每一个消息发送给其中一个(并且只发送一个)接收者(即一个订单处理模块)。 这样不同的订单可能会被不同的处理模块处理,但一个订单只会被处理一次。

当订单处理模块接收到一个消息,对它进行处理后将订单信息发送给仓库系统并更新订单数据库。处理完成后它会发出通知告诉服务 器可以删除此消息。通常这一系列和处理(接收,发送给仓库系统,更新数据库以及通知)会被作为一个交易来处理以保证它的完整性 (ACID)。

4.2.2. 消息的广播/订阅模式

这种模式中,多个发送者将消息发送到服务器中一个特定的实体,JMS中通常称为话题(topic)。 一个Topic常常有多个订阅者(subscription,即消息的接收者)。

与消息队列的接收者不同,每个订阅者都会收到发送的队列中的每个消息。

订阅者可以选择为固定的方式(durable)。采用这种方式的订阅者, 其消息会保留直到被接收为止。即使是其间服务器发生过故障或重启也不受影响。非固定的订阅者只在其连接期间有效, 一但连接断开其消息将不会保留。

电子消息订阅是消息广播模式的一个例子。当新闻被世界各地的编辑編好后,他们将其发关到新闻topic。 同样对这些新闻兴趣的读者会订阅这个topic。消息系统将保证每个订阅者都能够收到每一篇新闻稿。

4.3. 传送的可靠性

大多数的消息系统是可靠的消息传送系统。消息系统可以保证一个消息被传送 给一个并且只传送给一个队列的接收者或每个话题的固定的订阅者。一个消息不会被传送两次。即使在系统出现故障时也是如此。 这一特性对于很多企业来说是非常重要的。比如你想要保证订单不丢失或被处理两次以上,就可以利用该特性。

在某些情况下这种“一次并且只有一次”的传送方式并不是很重要,重复消息和消息的丢失并不影响系统的功能。比如股票价格 的更新消息,它并不需要保证每次都能收到,因为前一次更新很快就会被下一次代替。这样的功能消息系统也可以支持。

4.4. 交易(Transactions)

消息系统通常支持在一次本地交易中发送并通知多个消息。HornetQ还支持分布式交易。它可以通过Java的XA和JTA接口, 将消息的发送与通知做为一个分布式交易的一部分来完成。

4.5. 持久性(Durability)

消息可以分为持久消息和非持久消息。持久消息被保存到永久的存储介质中,不受服务器故障与重启的影响。非持久消息在服务 器故障与重启时则会丢失。像订单,交易信息属于持久消息,而股票价格更新由于它的即时性则可以做为非持久消息来处理。

4.6. 消息API和协议

客户端的应用程序怎样访问消息系统来进行消息的发送与接收呢?

一些消息系统提供私有的API,客户端可以通过这些私有的API与相应的消息系统交互,实现消息的收发。

除此之外,还存在着一些标准的交互方式可供使用。另外还有一些标准正在不断完善。下面我们就介绍一下这些标准。

Let's take a brief look at these:

4.6.1. Java消息服务(JMS)

JMS 属于Sun公司JEE规范的一部分。 它定义了一套标准的API支持消息队列和广播-订阅模式。JMS是一套非常精简的通用的标准,它将当时已经存在的消息系统的共同功能包括了进去。

JMS是一个广泛使用的API,绝大多数的消息系统都支持它。JMS只有Java的客户端才可以使用。

JMS并没有定义传输的格式(wire format)。因此不同的JMS消息服务器的和客户端相互之间通常不能交互,这是因为每个消息系统都自己的传输格式。

HornetQ全面支持JMS 1.1 API。

4.6.2. 专有的API

很多系统提供自己的一套API来与其消息系统进行通迅,其优势是它可以允许客户端使用其全部的功能。 像JMS那样的标准API往往不能提供许多消息系统所支持的额外的功能。

HornetQ提供了一套自有的核心API,客户端程序可以通过它充分利用HornetQ的强大功能。 这对于一些JMS API满足不了的需求是非常有用的。

4.6.3. RESTful API

采用REST REST[http://en.wikipedia.org/wiki/Representational_State_Transfer]方式与消息系统交互越来越被关注。

由于云计算技术的API标准目前倾向于采用REST的方式,所以采用REST方式的消息系统很有望成为云计算中消息传送的标准。

REST方式中的各种消息资源以URI的方式来定义。用户通过一套很简单的操作与这些资源相交互,如PUT、POST、GET等。HTTP通常用来作为REST方式的通信协议。

采用HTTP的好处是它很简单实用,并且internet经过多年的发展已经能很好的支持HTTP协议。

HornetQ将会很快地支持REST方式的API。

4.6.4. STOMP

Stomp 是为消息系统定义的一套简单的文本传输协议。它定义了一种线上传输的格式, 因此采用Stomp编写的客户端可以与所有支持Stomp的消息系统交互。Stomp的客户端可以用多种编程语言来实现。

有关在HornetQ中如何使用Stomp的详细内容请参见Section 45.1, “Stomp”

4.6.5. AMQP

AMQP 是一套可支持互操作的消息规范。 它定义了自己的传输格式,因些任何AMQP的客户端都可以和支持AMQP的系统进行交互。AMQP的客户端可以用多种编程语言来实现。

HornetQ将会很快地支持AMQP。

4.7. 高可获得性(Availability)

高可获得性是指在系统中有一个或多个服务器发生故障时仍然能够维持运转的特性。不同的消息系统对高可获得性的支持程度是不同的。

HornetQ支持自动失效备援(failover),也就是当主服务器出现故障时,当前的会话会自动连接到备用的服务器上。

Chapter 39, 高可获得性(High Availability)和失效备援(Failover)给出了HornetQ的HA特性的详细信息。

4.8. 集群

许多消息系统支持由多个消息服务器组成的集群。集群可以使发送和接收的负荷分散到不同的服务器中。 通过增加集群服务器,可以有效的增加整个集群处理消息的能力。

然而不同的消息系统有着不同的集群架构。有的集群架构十分简单,有的集群中成员间的联系很少。

HornetQ提供了非常先进的可配置的集群模型。根据每个节点接收者(consumer)的多少以及是否具有接收状态,消息在集群中可以进行智能化负载均衡。

HornetQ还能够在集群中的节点间进行消息的再分发,以避免在某个节点出现消息匮乏(starvation)现象。

有关集群的详细内容参见Chapter 38, 集群

4.9. 桥接(Bridge)和路由(Routing)

有些消息系统可以将一些分散在不可靠的网络(如广域网或internet)上孤立的集群或节点桥接在一起。

通常一个桥的作用是从一台服务器的队列上接收消息然后将消息再转发到另一台服务器的队列中。桥连接可以解决不可靠网络连接的问题。 桥有自动重新连接的功能。一旦网络连接中断,桥可以自动进行重试直到重新连接上为止。

HornetQ的桥接功能可以配置过滤表达式,以实现有条件的转发。另外,它还可以实现消息转换的功能(transformation)。

HornetQ还允许配置消息在队列之间进行路由。利用它可以完成复杂的路由网络以便在不同队列间进行消息转发与复制,形成一个互连的消息代理(broker)网络。

有关的详细内容将在Chapter 36, 核心桥Chapter 35, 消息的转发(divert)与分流给出。