一起学习
欢迎来到 Java 理论与实践专栏,这是由经验丰富的 Java 开发人员 Brian Goetz 撰写的一个新的专栏月刊。本专栏旨在探索设计原则如何满足解决实际问题的需求这一难以捉摸的结合点。每个月我们都将探索设计模式、可靠软件设计的原则以及为什么“最佳实践”是最好的,同时也关注如何将它们应用于实际问题。这个月,Brian 讨论企业消息排队技术。
最近几年,开发人员可以更广泛地得到企业消息排队(MQ)产品。适当地使用 MQ 技术经常可以改善应用程序的组织、性能和可伸缩性。Java 消息服务(Java Message Service (JMS))是集成到 J2EE 中的一部分,它使得 MQ 服务可以为任何 J2EE 应用程序所用。在本文(也是本专栏系列的第一部分)中,Brian 概述了在 Java 应用程序中使用消息排队的一些好处,并探讨了能够从 MQ 技术中获益最大的问题类型。请在论坛上(或者通过单击本文顶部或底部的讨论)同作者及其他读者分享您对本文的想法。
消息排队(MQ)工具没有数据库工具(例如关系(SQL)数据库)为人所知或为人理解,数据库工具是几乎所有企业应用程序和大量比较简单的应用程序中的关键组件。开发人员总是可以采用多种类型的数据产品,其范围包括从廉价的、只能在台式机上使用的数据库(例如 dBase 或 Microsoft Access),到工作组数据库服务器(例如 Sybase SQL/Anywhere),再到企业数据库服务器(例如 DB2 或 Oracle)。 无论您的项目是什么样子的,总有一个价格、性能及功能都适合的数据库产品可供您使用。
和数据库相似,MQ 产品有时被称为面向消息的中间件(MOM),已经出现相当一段时间了。然而,直到最近,MQ 服务器还一直是昂贵的、只能被资金最充足的企业开发人员所用的高端产品。结果,只有非常少的开发人员可以享受在其应用程序中使用消息传递所带来的好处。
大众化的消息排队
幸运的是,这一状况正在开始改变;现在市场上已经出现了几种价格较低的 MQ 服务器。1997 年,Microsoft 发布了 MSMQ,它是一个事务性消息排队产品,作为 Windows NT Server 中的集成部分 — 无需额外的许可费用。Sun 将 JMS API 包括在最初的 J2EE 规范中,这极大地促进了消息传递的大众化。在 J2EE 规范的版本 1.3 中,所有的 J2EE 容器都要求包含 JMS 提供程序(provider)。
JMS,也就是 Java 消息服务,它是一种允许 Java 应用程序通过标准化的接口访问范围广泛的 MQ 服务器(或者,按照 JMS 的说法,是提供程序)的 API,就象 JDBC 允许程序通过一个公共接口访问许多不同的数据库服务器一样。大多数 J2EE 容器包含 JMS 提供程序;将来,所有 J2EE 容器都将包含 JMS 提供程序。没有 J2EE 容器也可以使用 JMS;市场上有几种独立的 JMS 提供程序实现。此外,EJB 2.0 规范引入了一种新的 EJB 类型 — 消息驱动 bean — 它使得创建利用实体和会话 bean 的消息驱动的组件非常容易。
既然我们都可以使用 JMS 服务,我们就应该学会在应用程序中使用消息传递的能力。Willy Farrell 是 IBM 的一名电子商务设计师,他写了一本优秀的关于使用 JMS 的介绍性教程(参阅参考资料)。 它涉及创建消息和队列的基本知识,以及对消息划分优先级、检索消息和编码消息的所有选项。
消息传递和数据库起了相互补充的作用,在许多情况下,同时使用消息传递和关系数据库可以产生比只使用它们中的一个好得多的解决方案。
历史上,曾经将 MQ 服务器用于面向事件的应用程序(例如财务服务应用程序)或者作为一种与完全不同的系统进行相互操作的方式(例如连接完全不同的数据库应用程序或将一个企业同另一个在供应链网络中的企业相连接)。术语“面向消息的中间件”经常应用于 MQ 服务器,它强调 MQ 技术主要用途是连接完全不同的系统。然而,随着 MQ 产品成本的降低,许多其它应用程序现在也可以从消息排队中获益。
MQ 服务器做什么?
用 MQ 的说法,消息只是一个字节流(这个字节流可以是一个 XML 文档、一个序列化的 Java 对象、一个文本字符串或甚至是一条空消息)。对消息的解释留给应用程序域来做;MQ 基础结构不对消息施加任何语义和结构限制。消息存储在队列里,MQ 服务器允许您将消息加入到队列以及从队列中取走消息。
到目前为止,消息队列听起来很象简单的链表。从其最简单形式来说,的确是这样的,但是企业 MQ 服务器通过将一些功能特性封装进这一链表管理而增强了其功能:
控制谁可以向队列中写以及谁可以从队列中读的安全性
网络接口,它允许消息生产者和消费者位于不同的地方
事务性支持,这样入队和出队操作都具有事务特性:原子性、一致性、隔离性以及可持久性
分布式事务支持,这样队列操作可以同其它资源管理器(如 SQL 数据库)一起参加分布式事务
持久存储性
负载均衡
故障转移
管理
MQ 的长处
MQ 的长处源自消息处理的异步性质所带来的固有的松散耦合。一个实体向队列发布消息与另一个实体除去并处理消息的过程是完全分离的。这两个实体无须同时运行,也无须位于同一系统上,甚至无须知道另一个实体的标识;它们仅按照自己的时间表同队列交互。它们只须就彼此将接收的消息的格式达成一致;此外,它们无须知道对方的任何其它事情。
松散耦合有许多优点。它提供了一个自然的机制,将一个工作单元分成更小的、独立的组件,这种机制在处理请求的各阶段之间隐式地创建了抽象。这种细分允许我们方便地一个接一个地抽象每个组件的实现,更好地衡量和管理每个组件对资源的利用,或者使用提供具有类似功能的组件替换一个组件而无需改变其它组件。
JMS 规范要求 JMS 提供程序也实现发布和订阅功能,该功能允许您创建不同的、应用程序定义的且名称为主题的通道,并允许单个实体订阅这些主题。排队到主题的消息自动放置在任何订阅过该主题的实体的专用队列中。主题在财务服务或新闻发送应用程序中执行有价值的排序功能。例如,虽然有 5000 多种股票在美国的主要交易所交易,但每个投资者可能只对其中的 30 种股票感兴趣。因此您可以为每个订单符号创建一个主题,让用户订阅他们感兴趣的符号,然后让 MQ 引擎执行仅仅显示每个投资者想要的报价,避免发送重复的股价。用 SQL 数据库实现这一过程要困难得多。
经典的 MQ 用法模式
有一些最适合于使用消息排队的常见用法模式。当在您的应用程序中看到这些模式之一时,您应该考虑使用消息传递。
面向事件的应用程序
高度面向事件的应用非常适于使用 MQ 技术。这些包括财务服务应用程序(请考虑一个证券交易所,它显示股票价格更新,根据价格变化或其它订单的执行来启动交易,报告订单状态等等),新闻发送服务应用程序以及供应链应用程序。在金融市场中,必须对事件进行迅速处理;当发生了重要的事情时,您希望在它一发生时就得到通知。
轮询数据库
数据库在持久存储数据方面是非常优秀的,但是存储瞬时数据并在数据改变时通知我们却不是它们的长处。
虽然它不是高效的,但是轮询数据库却非常常见。每个机场的显示监视器不断轮询数据库以更新它们显示的信息。有许多出纳窗口的银行经常使用电子信号来指示下一个空闲出纳员的位置。电子商务站点内的订单处理系统可能轮询数据库以查看是否有任何新订单需要处理。或者保险索赔工作流系统可能轮询以查看是否有任何新的索赔可以分配给空闲的索赔调解人(claims adjusters)。
所有这些轮询都产生了许多额外的工作。如果有许多实体频繁地轮询(并且如果它们想要迅速地反映数据的更新,它们就必须这么做),就可能给数据库服务器和网络造成很大的负载。在大多数时候,轮询不返回数据,更糟的是,会返回我们已经见过的数据,但又必须再次处理或标识为已经处理过。
数据库不只是为轮询或事件而设计的。如果在事件发生或数据更改之后必须采取相对迅速的行动,那么异步消息传递是完成这一任务更容易和更有效的方法。无论何时在需要知道更新而轮询数据库时,请考虑使用 JMS 来替代数据库。
工作流
根据工作流门户网站(它是 Workflow Management Coalition 和 Workflow And Reengineering International Association 共同努力的结果)的定义,工作流是“……整个或部分商业过程的自动化,在这一过程中,根据一套过程规则,将文档、信息或任务从一个参与者传递给另一个参与者。”MQ 解决方案特别适合于工作流应用程序(例如文档路由和批准、保险索赔处理等等),这是因为 MQ 技术对如何处理大量使用纸张的办公室里的工作流问题进行了精细的建模,在这种办公室内每个参与者都有一个收件箱和发件箱。
工作流应用程序的特征是有许多代理(代理可以是人,自动处理步骤甚至是物理装备,例如机器和打印机),每个代理都执行任务的一小部分并将其传递给由业务规则所确定的下一代理。请考虑批准和支付电子支出报表这一过程。雇员创建并提交报表,接下来该报表需要由雇员的经理批准(如果美元数目超出了规定的数目,则需要由另外一级管理部门批准)。接下来到了人力资源部,在那里对它进行核查以确定其准确性,还要进行细查以确保该开支是有效的业务支出并符合公司的政策。如果批准了,将会创建支付请求并安排打印支票。这之后,可能进入财务部,在那里单个收费记录将会应用到适当的帐户和成本中心。在这些阶段的每一个,支出报表都可能被弹回给雇员或雇员经理。
在构建工作流应用程序过程中,主要设计目标是确保工作能够从一个代理迅速地传入到另一个代理,并确保任务不崩溃。MQ 服务器同数据库一起携手工作,它使得向您的应用程序中构建灵活、可伸缩、可扩展的工作流处理变得容易。
使用 MQ 以从关键路径去除风险大的操作
在电子商务或供应链应用程序中的接收、批准和填写订单同工作流应用程序有许多共同之处,虽然大多数步骤涉及的是电子参与者而不是人。接收并履行订单可能会包含下列步骤中的一些或全部:
接收订单并将其存储在数据库中。
对于消费者顾客,验证信用卡。
对于商业顾客,通过信用报告代理处或通过您公司的信用部门检查该顾客的信用。
执行一些欺诈核查分析。
核查库存。
在有多个履行中心的情况下,决定由哪个中心填写该订单。
向顾客发送一封确认电子邮件。
向顾客的销售代表发送一个通知。
生成挑选列表并将其交付给履行中心。
交付订单。
向用户收费并给其开票据。
由于您不想顾客在为获取确认号码和收据而单击“Buy”之后等很久,因此无论在提交之后执行哪一条代码,该代码路径都应该简短并且有可预见的执行时间。但是这些步骤中的许多步骤都需要访问一些资源,这些资源在客户下订单时可能可用也可能不可用,或者这些资源的响应时间可能无法预料。在这种情况下,应该从关键路径去除它们;让订购的启动动态设置事件链,而通过将提交步骤的工作减到绝对最小来开始订单,来尽可能快地使用户脱离循环。除了将给顾客一个更好的用户经历之外,将订单处理分成多个离散的(较短)的步骤还改进了资源利用并减少了竞争 — 这意味着事务更短(因此锁定也释放得更早),并且在一步(例如网络和数据库连接)中所用到的资源也释放得更早。
在订单处理过程中,最不可预见的步骤之一是发送确认电子邮件。邮件服务器经常会拥塞,可能会要好长时间才能接收一条消息,也可能完全拒绝连接。如果顾客的邮件服务器拒绝确认消息,那么您就想要稍后重新尝试发送该消息。这样,发送确认电子邮件就“有风险”,这是因为第一次发送可能不成功,或者发送需要很长时间来处理,而您又不想让顾客(或有关这件事的任何其它的东西)一直等到确认到来。类似地,库存可能存储在同订单处理分离的数据库中(库存数据库可能由一个外包的履行服务拥有),并且在订购时可能不可用。或者信用部门可能在星期五不上班。
通过使用消息队列来存储暂挂的确认电子邮件、库存检查或者信用检查,您可以将“有风险的”操作同过程的其余部分分离,因此也使过程的其余部分避免了操作失败或花费很长时间的风险。由于每个处理步骤只完成一项简单的任务,因而也将极大简化了每个任务的错误处理。
结束语
如果应用得当,消息排队技术通过将任务分解成子任务,可以极大地简化复杂任务的处理,还能增加应用程序的灵活性和可伸缩性。自 J2EE 版本 1.3 起,每个 J2EE 容器都将包含一个 JMS 提供程序,这意味着我们都能在我们的应用程序中利用异步消息排队的强大功能。
下个月,我们将探索 Java 事务服务(Java Transaction Service (JTS))的工作原理了。虽然它不如 EJB 或 J2EE 的其它元素引人注意,但 JTS 可能是 J2EE 的最关键部分 — 事务使我们能够构建可靠的分布式应用程序。我们将在今后的某篇专栏文章中重述 MQ,并且构建一个工作流应用程序,以演示消息排队和关系型数据库是如何相互协作和取长补短的。
参考资料
请通过单击本文顶部或底部的讨论来参与关于本文的论坛。
从 Sun 获取关于 JMS 的规范、参考资料和示例。
Richard Monson-Haefel 和 David Chappell 的 Java Message Service (O'Reilly and Associates,2000)全面介绍了 JMS API 并提供了许多运用它的实际示例。
Richard Monson-Haefel 的 Enterprise JavaBeans (O'Reilly and Associates,2000)是一个全面更新的版本,它详细介绍了 EJB 2.0 规范中的变化。
Willy Farrell 在他的教程 Introducing the Java Message Service(developerWorks,2001 年 8 月)中对 JMS 做了一个极好的概述,并提供了开发使用 JMS 的程序的基础知识。
作为 IBM 的电子体系架构设计师,Willy Farrell 对于如何使用 MQSeries 和 VisualAge for Java 来开发和测试 JMS 应用程序十分精通。他的两部分系列文章 Writing Java Message Service programs using MQSeries and VisualAge for Java, Enterprise Edition 和 Writing Java Message Service programs using MQSeries and VisualAge for Java, Enterprise Edition, Part 2 中有详细的论述。
Gordon Van Huizen 的 Messaging: The transport part of the XML puzzle(developerWorks,2000 年 7 月)介绍了主要传输层选项,并比较了它们如何可靠地在各方之间传输 XML。 您将发现有关 XML-RPC、SOAP、WDDX、ebXML 和 JMS 用于 XML 传输的方法的概述。
e-workflow 工作流门户网站是 Workflow Management Coalition 和 Workflow And Reengineering International Association 共同努力的结果,它为开发工作流应用程序的工程师提供了全面的参考资料。
MQSeries Primer 是一份 IBM 红皮书,它提供了企业消息传递中所用概念及术语的清晰的解释。
在 WebSphere 开发者园地中的 MQSeries with JSP technolog 这篇文章中学习如何与 JSP 技术一起使用 MQSeries。
Ryan Cox 描述了为 WebSphere 配置 JMS 服务。
在 developerWork Java 技术专区查找与 Java 有关的其它参考资料。
关于作者
Brian Goetz 是一名软件顾问,过去 15 年来他一直是一名专业的软件开发人员。他是位于加利福尼亚州洛斯阿尔托斯市 Quiotix 的首席顾问,该公司是一家软件开发和咨询公司。请阅读流行的业界出版物上 Brian 的已出版和即将出版的文章。可以通过 brian@quiotix.com 和他联系。
下载本文示例代码
应该在下一个企业应用程序中使用 JMS 吗?应该在下一个企业应用程序中使用 JMS 吗?应该在下一个企业应用程序中使用 JMS 吗?应该在下一个企业应用程序中使用 JMS 吗?应该在下一个企业应用程序中使用 JMS 吗?应该在下一个企业应用程序中使用 JMS 吗?应该在下一个企业应用程序中使用 JMS 吗?应该在下一个企业应用程序中使用 JMS 吗?应该在下一个企业应用程序中使用 JMS 吗?应该在下一个企业应用程序中使用 JMS 吗?应该在下一个企业应用程序中使用 JMS 吗?应该在下一个企业应用程序中使用 JMS 吗?
阅读(138) | 评论(0) | 转发(0) |