内容


Geronimo 叛逆者

Apache Geronimo 的 JMS 实现:ActiveMQ

James Strachan 访谈

Comments

系列内容:

此内容是该系列 # 部分中的第 # 部分: Geronimo 叛逆者

敬请期待该系列的后续内容。

此内容是该系列的一部分:Geronimo 叛逆者

敬请期待该系列的后续内容。

获得消息

Java™ 2 Platform, Enterprise Edition(J2EE)应用服务器并不是一个简单的软件。它有许多必须相互通信的组件。它还必须支持应用程序中的 Enterprise JavaBeans(EJB)相互通信。还必须考虑到,当需要创建集群解决方案(涉及多个位置的多台计算机上的多个实例)时,会发生什么情况。在 Geronimo 叛逆者专栏 中已经对集群进行了相当多的讨论,现在要注意的一个领域是系统中的消息传递。

显然,不具备消息传递解决方案的应用服务器是没什么用的。实际上,根本不可能存在不具备消息传递解决方案的 J2EE 应用服务器;JMS 标准的实现是 J2EE 规范的要求之一。在 Apache Geronimo 技术中,这是通过集成来自 ActiveMQ 项目的软件而实现的。

在走了几次弯路之后,包括一个糟糕的 Internet Relay Chat(IRC)客户机,我最终与 Apache Geronimo 和 ActiveMQ 的创建者之一 James Strachan 谈到了这个软件 —— 它是什么,它起什么作用,以及它对 Geronimo 项目的意义。由此,我在面向消息的中间件(MOM)方面上了一课,而且看到了面向服务体系结构(SOA)的未来发展。

进入 ActiveMQ

“我并不是说 ActiveMQ 由 Apache Geronimo 项目发展而来,” 当我建议谈谈 ActiveMQ 时 James 说,“但 Geronimo 项目的启动促使我们进行 ActiveMQ 的开发。” J2EE 规范要求有符合 JMS 1.1 的消息传递提供者,“所以我参与创建了 ActiveMQ 项目。”

许多人没有意识到:尽管可以从 Sun Microsystems 站点下载 JMS 1.1,但是这只是一个参考实现。如果想在自己的项目(尤其是开放源码项目)中支持这个消息传递框架规范,很可能需要编写自己的 JMS 1.1 规范实现。

这就是这个团队所做的。实际上,ActiveMQ 是一个独立于 Geronimo 的项目,尽管有许多人同时参与了这两个项目,包括 James、Dain Sundstrom、Geir Magnusson、Hiram R. Chirino、Greg Wilkins、David Jencks、Alan Cabrera 和 Aaron Mulder。不但可以在其他应用服务器中使用 ActiveMQ,而且即使根本没有应用服务器,也可以使用它。例如,如果要开发一个需要来回传递消息的应用程序,那么可以使用 ActiveMQ 而不是 JMS 参考实现。James 指出,“许多人将 ActiveMQ 用在 Spring 和 Tomcat 上。”

目前,ActiveMQ 还在 Apache Incubator 中,这意味着它还没有被 Apache Software Foundation 正式接受,但是正在向这个目标发展。“这是进入 Apache 的过渡阶段,” James 解释道,“就像是气密舱,项目可以进入其中,迁移到 Apache 基础设施,并学习如何成为 Apache 的一部分。” 这涉及到理解投票过程、建立项目管理委员会和其他活动。

Incubator 还要为项目建立一个活跃的社区,所以团队的多样性是很重要的。“Apache 不希望成为厂商推广产品的地方,” James 说,“他们希望有一个活跃的由各种人员组成的社区。”

社区也是 ActiveMQ 选择作为 Apache Incubator 的一部分的原因,因为它的社区实际上是 Geronimo 项目的一部分。“另外,” James 补充说,“我们发现各个公司开始自愿地向 Apache 捐献软件授权、许可协议和 IP 策略。”

但是,ActiveMQ 究竟是做什么用的呢?我与 James 谈了相当长一段时间之后,吃惊地发现,我们甚至没有提到集群。所以,这时我意识到 ActiveMQ 一定不只是为集群服务的。实际上,ActiveMQ 在 Geronimo 的 MOM 中处于中心位置。

什么是面向消息的中间件?

顾名思义,面向消息的中间件就是通过使用消息(而不是直接命令)将企业内的组件连接起来的系统。“它们是原始的 SOA 之一,” James 指出,“MOM 在许多年前就流行了,它作为使用高性能异步消息交换将松散耦合的系统连接在一起的方式。例如,库存系统可能会与工资和会计系统进行通信。如果使用 MOM 将它们连接在一起,就可以在任何时候关闭任何系统,发送到这个系统的消息会放在队列中,直到系统恢复工作。这样,就可以在平台、语言、API 和(最重要的)时间方面对系统进行松散耦合。”

我问 James,除了简单地提交和接收消息之外,MOM 还有什么作用。他解释说,它提供了两个基本服务:发布/订阅和队列功能。

发布/订阅 系统中,消费者告诉系统它正在寻找关于某一主题的任何信息。这个主题可以是很明确的,比如某只股票的价格更新,也可以是比较宽泛的,比如来自数据库的事件。当生产者产生这种消息时,客户机就会收到它们。通常,消息不是从生产者直接发送给消费者,而是由一个代理来管理消息,代理确保正确地对消息进行分发。

队列 系统中,无法立即提交的消息会保存在队列中,当适当的时候再提交。按照这种方式,如果消费者不在线,消息也不会丢失。“MOM 通常使用持久性消息传递,” James 解释说,“一些消息被写到硬盘上,这样就不会丢失了。例如,如果一个消息是 please deduct $1000 from bank account foo。您肯定不希望丢失这个消息或者由于意外发送它两次。”

这就是 MOM 的作用:精确地按照您希望的次数,将消息可靠地提交到准确的位置。

MOM 与 Web 服务

在 10 多年时间里,已经使用 Common Object Request Broker Architecture(CORBA)、Remote Procedure Call(RPC)或 EJB 等技术构建了这些系统。这些技术的问题是,它们对于单一系统工作得非常好,但是它们通常是同步的(这意味着在发送和接收消息时所有其他处理都会停止),而且依赖于位置。另外,系统通常涉及组件之间的紧密耦合。

当然,近来紧密耦合问题已经解决了,SOA 出现了。人们常常将 SOA 与 Web 服务混为一谈,但是这两者不是同义词。Web 服务,比如基于 Simple Object Access Protocol(SOAP)和其他 XML 协议的 Web 服务,对于跨越组织边界的应用程序是很合适的。“Web 服务的目标是成为一种开放式连接协议,” James 说,“而 MOM 通常对连接的每一端都进行控制。”

SOA 的开放性使得它得到了迅速发展。通常只有大型且先进的公司才使用 MOM,Web 服务大大扩展了这个市场。

但是,这两者并不是相互排斥的。通过 MOM 系统发送 SOAP 消息并不少见,有的 MOM 系统还实现了 WS-* 标准。实际上,ActiveMQ 已经实现了 WS-Notification,这是发布/订阅范型的 Web 服务版本。

另一方面,作为一种成熟得多的技术,在遇到其他需求(比如可靠的消息传递)时,MOM 比 Web 服务有优势。James 说,“HTTP 没有可靠性或正好一次 提交语义。”

他给我看了他写的一些关于 WS-ReliableMessaging 与 MOM 问题的博客,他在其中指出,“在 JMS/OpenWire/MOM 中,有办法指定每次消息交换的服务质量。” 换句话说,可以决定服务质量或需求,包括有保证的提交、消除重复提交,等等。James 接着说道,“WS-RM 基本上只处理消息确认(以及传递的次序和重复的次数是否正确),所以现在仍然需要有某种 WS-* 规范来控制其他各种服务质量,从而可以在使用 WS-RM 提供者时作为策略指定,而这些在 MOM 中早就存在了。”

另一个问题是性能。“如果您控制连接的两端,” James 解释道,“那么由于各种原因,使用 JMS/MOM/[Microsoft Message Queuing] MSMQ 提供者一般来说总是比 WS-RM 快,MOM 是基于连接的,不需要分析 XML 标记,而且多年来消息传递问题已经经过了充分的研究,厂商提供的实现已经很完善了。另一个好处是,MOM 可以与组织中遗留的非 WS 应用程序很好地配合。(大多数组织目前还拥有大量的 MOM 应用程序。)

“但是,WS-RM 的主要目的是在不同的消息传递系统之间建立桥梁,比如 Windows Communication Foundation(WCF)和其他 JMS/WS/[Enterprise Service Bus] ESB 栈,所以它不必比已经建立的 MOM 更出色。它的设计目的不一样,它寻求的是消息传递系统之间的互操作性,而不是最好的消息传递系统。”

同样,ActiveMQ 是 Geronimo 在尝试解决这些互操作问题过程中的成果。

ActiveMQ 和 Geronimo?

ActiveMQ 用在 Apache Geronimo 应用服务器中的许多地方,其中一些比较明显。我们已经大量讨论了消息传递和集群,所以就不着重讨论了。

ActiveMQ 使用 Java Connector Architecture(JCA)与 Geronimo 集成起来,这是一个 “用于 J2EE 的连接和线程池体系结构,可以处理任何协议,比如 JMS、JDBC(Java Database Connectivity)等等,” James 说。“它还处理异常处理和事务等问题,” 他补充说,“它是将 JMS 提供者这样的东西干净地与应用服务器集成起来的好方法。” 为了支持这样的集成,ActiveMQ 被包装在一个资源适配器中。这个资源适配器使任何应用服务器都能够对 ActiveMQ 发送和接收信息。

这种方法使 Geronimo 能够将 ActiveMQ 用于多种用途。除了进行集群之外,ActiveMQ 还作为 JMS 代理。这个代理是 JMS 解决方案的服务器端组件,负责路由、持久化、恢复,等等。它还包含一个 JMS 客户机,这个客户机使用户能够创建使用消息驱动 bean(message-driven bean,MDB)的应用程序,MDB 是一种只用来处理这些消息的 EJB。

“例如,” James 说,“您可能接收到一个向站点进行注册的 HTTP 请求;开发人员往往不在 servlet 中检验电子邮件地址,而是向一个队列中发送一个消息,让另一个服务来执行注册。同样,EJB 可能决定将处理工作委托给其他组件,这时就可以使用 JMS 发送一个请求。

“JMS 的常见用途是:(1) 可靠地异步处理负载平衡、故障转移和集群;(2) 对缓存/状态进行分布;(3) 实现实时 GUI,比如实时显示价格变动。”

在不使用 Java 技术的情况下在 Geronimo 中访问 JMS

换句话说,Geronimo 的 ActiveMQ 实现让您能够构建一个 GUI 应用程序,让它使用 JMS 客户机与应用服务器进行通信,所以不需要 Web 页面。ActiveMQ 还支持 Stomp 项目,这是一种与 JMS 代理进行交互的方式,非常简单而且独立于语言。因为它只要求打开一个套接字(比如使用 telnet),所以使用任何语言的客户机都能够与 JMS 代理进行通信。这样的 “交谈” 可能就像 清单 1 这样。

清单 1. 与 JMS 代理的 “交谈”
CONNECT
login: myUsername
passcode: myPassword

^@

CONNECTED
session:<someuniquevalue>

^@

SEND
destination:/queue/thingsIllDoToday

Make sure to receive any changes to the weather in Toledo.
^@

SUBSCRIBE
destination:/topic/weatherChanges

^@

MESSAGE
destination:/topic/weatherChanges
message-id:<someuniqueidentifier>

Temp: 62
^@

MESSAGE
destination:/topic/weatherChanges
message-id:<someuniqueidentifier>

RainChance: 60
^@

MESSAGE
destination:/topic/weatherChanges
message-id:<someuniqueidentifier>

Temp: 60
^@

每个消息(即帧)以一个命令开头,以一个表示 null 字符的 ASCII 符号结束。在这个例子中,我将从服务器发送到客户机的消息显示为斜体,以便区分。在这里可以看到,一个客户机连接到这个系统,它将一个消息发送到队列 thingsIllDoToday,然后订阅 weatherChanges 队列。代理每当接收到属于这个队列的消息时,就把消息发送给这个客户机。

Stomp 项目已经开发了 Ruby、Python、Perl、PHP、C、C# 和 Java 语言的客户机。还可以使用二进制连接格式 OpenWire,这实际上是 ActiveMQ 的默认连接协议。它比较快,但是比较难实现。

消费者端的负载平衡

James 还告诉我,他最欣赏的 ActiveMQ 特性之一是可以在消费者端进行负载平衡。消息组是一种不太为人所知的 JMS 可选特性。“它有点儿像 Web 应用程序的负载平衡,但是应用于消息传递,” 他说。假设您将来自 Amazon 站点的订单放进一个队列中,希望尽可能快地处理它们。JMS 提供者会在消费者之间根据负载平衡原则分配这些消息。但是,如果希望按照次序处理消息,就会遇到一个问题:只能使用一个消费者来处理消息,这样才能保证次序的完整性,才能正确地处理订单。

“所以,如果我们的集群有 1,000 个消费者,可以将 JMSXGroupID 字符串添加到每个消息中,表示它属于哪个组,这样就可以维持消息的次序。例如,可以使用 Books 作为 ID。这样就由一个消费者来处理所有图书,而 Electronics 和其他类别的商品仍然进行负载平衡。还可以使用图书的 ISBN 号作为 ID,这样所有 Getting Things Done 图书由一个消费者处理,JMS Essentials 图书由另一个消费者处理。所以,它是一种有亲和性的可定制的负载平衡,可以支持故障转移。如果一个消费者停止工作了,那么另一个消费者会替代它。甚至可以将当前拥有的图书数量缓存在消费者中,因为在整个集群中只有这一个线程处理这种书的订单,所以其他消费者不会修改数据库。所以可以进行超高效率的缓存,避免锁定和争用问题。这是一种对应用程序进行划分,从而使吞吐量最大化的好方法。”

Geronimo 和消息传递的未来发展

现在,似乎寻找通用的消息传递解决方案更容易了,这种想法既正确也不正确。即使在这个 Web 服务大肆流行的世界中,实现消息传递的方式仍然日益增多。JMS、CORBA、SOAP、Remote Method Invocation(RMI)、EJB,我可以一直列举下去。这种不断复杂化的局面让我这样的开发人员觉得害怕,但是 James 认为不需要如此担心。

“重要的是,开发人员往往把 JMS 和 EJB 这些东西想得太复杂了,” James 告诉我,“所有中间件工作的实际操作正在隐藏在 Plain Old Java Object(POJO)后面。这方面的尝试包括 EJB 3、Spring Remoting 和 Service Component Architecture(这可以在 Apache Tuscany 中看到)。所以,开发人员不必选择使用 JMS API、EJB API、RMI、CORBA 或 SOAP,他们只需部署自己的 POJO 并在容器中启用中间件。

“甚至可能将中间件完全隐藏起来,这样应用程序开发人员只需编写业务逻辑,而让容器来处理中间件的琐碎工作。”

目前,Apache Geronimo 还有另一个涉及 ActiveMQ 的方便特性:ServiceMix。ServiceMix 是一个依赖于 ActiveMQ 的 ESB,但是它允许集成来自所有类型的环境的消息。启用 ServiceMix 中的 Java Business Integration(JBI),这样系统就可以接收来自各种来源的消息,比如文件、电子邮件、Jabber、SOAP、来自其他启用 JCA 的组件的消息等等,并让它们一起工作。ServiceMix 将是 Geronimo 1.2 版本的一部分。

结束语

我们处于面向服务的环境中,在这种环境中消息传递并不是锦上添花的东西,而是必需的。Geronimo 用来提供消息传递服务的 ActiveMQ 实现本身就是一个有用的项目(在 Geronimo 内外都是),感谢 James Strachan 花时间与我们对它进行了讨论。


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Open source, Java technology, SOA and web services
ArticleID=133871
ArticleTitle=Geronimo 叛逆者: Apache Geronimo 的 JMS 实现:ActiveMQ
publish-date=06222006