在使用本文描述的技术之前,请确保您熟悉以下系列文章中介绍的启用网格应用程序的 6 种策略:
- 第 1 篇文章“ 启用网格应用的六种策略,第 1 部分: 概述”概要介绍了这 6 种策略,并总结了每一种策略的特性及带来的好处。
- 第 2 篇文章“ 启用网格应用的六种策略,第 2 部分: 策略 1:简单批处理和策略 2:独立并发批处理”展示了如何用这两种策略启用网格应用程序。在策略 1 中,应用程序可以在众多网格计算机中的任何一台上执行一项作业。在策略 2 中,多个独立的应用程序实例可以并发地运行。
- 第 3 篇文章“ 启用网格应用的六种策略,第 3 部分:策略 3:并行批处理和策略 4:服务”讨论用这两种相互排斥的策略启用网格的方法。在策略 3 中,批处理作业被细分。它的众多独立子作业可以根据提交作业的用户的指示,独立地运行。策略 4 讨论了在网格环境中实现面向服务的架构。
- 第 4 篇文章“ 启用网格应用的六种策略,第 4 部分: 策略 5:并行服务”向您展示了如何为一个服务同时启动多个实例,同时每一个客户机都可以并行利用这些实例。
本文首先介绍了基本的架构模式,它适用于大多数在已有代码中启用网格的应用程序。接下来,我们讨论如何根据这些年来最经常遇到的架构启用已有的代码。我们将介绍两种基本的与特定于平台的分布式系统,我们将研究每种场景的最常用架构变体,以及使这些架构适应于启用模式的最常用方法。最后介绍两种关于支持 Web 的应用程序(以 servlet 为中心和以数据库为中心)的场景。
对已有代码用面向批处理的网格基础设施软件启用网格时,大多数工作都很相似。下面是一种可以遵循的模式。您可以用这一模式来实现采用网格的前 3 种策略。
在这 3 种采用网格的策略中,基本案例是一个程序,它获取命令行参数,并根据命令行参数中指定的值来使用文件或数据库。如果程序是已授权的,则网格基础设施将要求具备许可管理的功能。
从一般意义上讲,前 3 种在已有应用程序中启用网格的策略都需要用户向客户机应用程序发送请求,这时,客户机在网格基础设施中扮演着请求者的角色。客户机应用程序的客户机可以是真正的用户,也可以是一个门户。网格基础设施负责部署实际的应用程序,而后者则成为网格基础设施中的提供者。请参阅图 1。
图 1: 用集成模式启用已有代码
关键点在于客户机程序(作业提交驱动者)与网格基础设施对话的方式应该和它直接与应用程序对话的方式相同。要实现这一点,最简单的方式就是让客户机程序向虚拟的应用程序发送命令行类型的指令。
如果应用程序是一个独立的程序,具有最低的部署需求时,这种场景很容易实现。但是当您处理集成应用程序时,整件过程就需要一点创造性。
由于当今软件产业的现状,我们用面向批处理的网格基础设施软件启用已有代码时,会涉及到数目有限的已知场景。这里存在两种场景,本质上都牵扯到同一类型的应用程序:
- 启用特定于平台的分布式应用程序,如在 Web 应用程序出现之前编写的客户机/服务器、事务性、以及面向批处理的应用程序等等。
- 启用支持 Web 的应用程序,其中包括特定于平台的分布式应用程序,它们通过提供“Web 前端”或“封装器”使得 Web 应用程序工作。在大多数情况下,这种集成策略都涉及启用以 servlet 为中心的或者以数据库为中心的应用程序。
前面提到,这种场景适用于客户机-服务器、事务性、以及面向批处理的应用程序等。在这三种类型的应用程序中有两种架构倾向十分流行:单片式和模块式。
一般意义上讲,在面向批处理的网格基础设施软件上部署特定于平台的单片式应用程序非常简单,即,在所有网格节点上都安装应用程序,然后编写一些“胶水代码”,集成用户请求、参数传递、网格基础设施中的程序调用等。请参阅图 2。
图 2: 用标准的启用模式部署单片式应用程序
这里所说的“胶水代码”使启用应用程序成为一种集成工作。在大多数情况下,您可以通过脚本将单片式应用程序和面向批处理的网格基础设施产品集成起来。您可以使用 Perl、Python、或普通的 shell 脚本将用户请求、参数传递、应用程序调用等集成到网格基础设施软件的上下文中。
警告和单片式应用程序的功能及其实现方式有关。单片式应用程序倾向于替所有人做所有工作。这也正是它们被称为单片式的原因之一(对有些人来说模块式的应用程序不是可信赖的)。有些时候,除了其他功能之外,单片式应用程序还嵌入了网格的功能。嵌入的部分以及这些功能的实现方式决定了应用程序是否能在网格中运行。
举个例子来说,单片式应用程序中如果不具备任何内置的网格基础设施功能,就比其他应用程序更容易启用。一个例子就是类似的应用程序,它对它应该做什么了如指掌,并且在意以下时间安排任务,如哪个实例处理哪个请求,或哪个数据库表需要针对给定用户上锁,或决定何时需要强制实现事务关系等等。然而,我们依然需要深入地了解内置网格功能的实现方式。
如果内置的网格功能可以在应用程序内部关闭,那么毫无疑问,这种单片式代码片断肯定能够在面向批处理的网格基础设施软件顶端运行。否则,如果网格功能深深地根植在应用程序内部,并且不能关闭,事情就麻烦了。
一般情况下,关闭内置网格基础设施功能所需付出的工作非常之多。当程序员学习重用代码时,他们也学习了在两种方向上对功能进行抽象:向上和向下。在业务逻辑框架中嵌入网格基础设施的特性就是将功能进行向下抽象的例子。
我们不能埋怨程序员这样做。大多数特定于平台的分布式应用程序在编写时,很少有人能够考虑到网格计算。那时候甚至没有人会想到还可能用已经成型的容器来容纳他们的应用程序,更不用说用完善的网格基础设施部署其代码了。
一般情况下,启用模块式的特定于平台的分布式应用程序比启用单片式应用程序要简单。这样说的原因是模块化应用程序中提供了如何部署的选择。与前面的情况一样,这也存在需要警惕的问题,但是对于模块式应用程序,解决起来也更加容易。
模块式应用程序的主要优点之一就在于可以在需要的时候将模块关闭。采用这种方式后,任何与环境相关的功能都可以呈交给网格基础设施。
与单片式应用程序的情况类似,内置网格特性的存在,及其是否能够被关闭和剥离,也会决定启用网格时工作的难度。
不同指出在于,大多数模块式应用程序只要具有任何内置网格特性,都很可能将这部分功能集中在单个模块,或是一组特殊的模块中。这样从理论上讲,关闭模块或是完全清除这些模块就更加容易了。
这次的警告涉及模块间的通信。关闭或剥离应用程序模块的难易程度取决于设计者如何实现模块间的通信。一般情况下,传输方式越简单,困难程度越低。
比如,在这种应用程序中通常具备专门负责处理所有数据库调用的模块。在某些情况下,这个模块并不仅仅是通过支持多家供应商的 ODBC 或 JDBC 驱动程序而成为通用数据库客户机,而且,还可以实现我们称之为“表访问时间安排”的机制,这是一种应用程序内部的表锁定机制,允许应用程序独立于数据库对表锁定进行处理。
拥有通用数据库客户机是个好主意。然而,如果应用程序要启用网格,就最好把表锁定的任务交给数据网格基础设施来处理(假设用这种方式来处理该应用程序)。那么,我们需要做的全部工作就是用这个模块代替常规的数据库客户机,将 RDBMS 部署到数据网格中,然后就得到了一个启用网格的应用程序。
大多数数据库客户机和监听器都依赖于 TCP/IP 套接字从程序中获取命令。比如,DB2® 客户机监听的默认端口是 50000。但是如果应用程序设计者认为 TCP/IP 套接字的 tried-and-true (尝试然后发现是对的)方法对他们的应用程序不够理想,该怎么办呢?如果他们决定用一种私有机制实现模块间通信,又该如何?这时,问题就不再简单了。
关于模块间通信还有另一方面的问题会妨碍工作继续进行。如果应用程序打算部署在计算网格中,那么网格中将会有多个模块的多个实例并发运行。如果网格基础设软件不能依赖这种传输机制,或是如果传输机制本身不能在网格环境中运行,那么这个用程序就无法像预期的那样工作。
那么,启用网格项目的复杂程度就直接与替换模块间通信机制付出的努力成正比。
一个理想的模块式应用程序应该用一个调度程序(或代理调度程序,即broker)模块处理模块间的通信。这种规划使得模块能够部署在网格中的任何地方,因为模块间通信的机制总是通过代理调度程序实现的。请参阅图 3。
图 3: 模块式应用程序部署的理想方式
最佳案例场景具有两种非常吸引人的行为。第一,应用程序模块应该是原子的,以允许独立部署。调度程序/代理调度程序应该负责负责所有模块间通信和数据交换。
对于共享库来说,如果它们是作为系统级安装的一部分进行安装的,那么网格基础设施应该能够处理这些库。否则,可以作为所有模块供应策略的一部分,这样所有节点都会有一份本地副本。
第二,应用程序模块的粒度应该足够小,以便同一模块的多个实例可以在同一台机器上并发(至少)运行。模块应该负责收集自己的结果。应用程序级的结构收集可以通过调度程序/代理调度程序来处理,也可以通过数据库实现。
遗憾的是,大多数模块式应用程序都没有那么好。在某些情况下,对模块的封装不够原子化,不能支持真正的独立部署。在另一些情况下,调度程序/代理调度程序模块并没有处理所有模块间通信和数据交换。而是,有些模块直接相互调用,那么这些模块就必须位于相同的机器上。
尤其是当调度程序/代理调度程序没有完全负责模块间通信时,结果收集也会出现问题。有些模块可能将其运行结果交给其他的模块,而不是直接传递回代理调度程序。不管是哪种情况,最常见的情形是,在所有网格节点中部署整个应用程序,如图4 所示。
图 4: 模块式应用程序部署的最常见方式
从某种程度上讲,最常见的场景意味着如果出现最糟糕的情况,模块式应用程序可以作为单片式应用程序来部署。应用程序应该能够工作,但是却失去了模块式应用程序的优点,因为网格基础设施不能像理想案例中那样利用它。
同样,可以将单片式应用程序看作只有一个模块的模块式应用程序,在多个并发实例的情况下,制订结果搜集的管理策略时,也可以将其这样看待。
单片式应用程序和模块式应用程序这两种情况,代表了在特定于平台的分布式应用程序中启用网格时遇到的最简单的场景。我们处理支持 Web 的应用程序时,情况会发生动态变化,这一点将在下节中讲到。
支持 Web 的应用程序并不是真正的 J2EE 应用程序。我们将那些最初作为特定于平台的分布式应用程序编写,但又通过 Web 前端等技术作为 Web 应用程序运行的应用程序称为“支持 Web”的应用程序。
最常见的架构称为以 servlet 为中心和以数据库为中心,它们在启用网格时都具有其自身的挑战。
以 servlet 为中心的应用程序一般情况下遵循如图 5 所示的架构模式:
图 5: 以 Servlet 为中心的最常见架构模式
图 5 中特定于平台的应用程序在某些情况下会用补丁的方式支持诸如 XML 之类的技术。可以通过 JNI 或适当的连接器框架与 Java 虚拟机进行通信。至于对数据库的支持,通常使用 ODBC-JDBC 桥,也可以依然使用 ODBC。
当以 servlet 为中心的应用程序移植到 J2EE 应用程序服务器上运行时,会通过一个网关 servlet 与客户机交互,而这个 servlet 则将请求传递给上面所说的连接器,然后再传给真正的应用程序。向诸如 WebSphere® Application Server(WAS)等应用程序服务器移植的典型过程如图 6 所示:
图 6: 以 servlet 为中心应用程序的典型 Web 启用策略
遵循这种执行模式的应用程序要在网格中运行,至少要求完成下面的步骤:
- 修改部署描述符,这样实际部署在 WAS 中的只有网关 servlet,它同时也将成为用户的门户。
- 将连接器框架中 Java 接口的部分(JNI 或其他私有代码)放在核心应用程序中,并部署为一个独立的 Java 应用程序。这将成为客户机程序或作业提交驱动程序。
- 将应用程序的核心在面向批处理的网格框架中部署为单片式或模块式应用程序(哪个术语适合就用哪个)。
结果场景如图 7 所示。
图 7: 典型的以 servlet 为中心应用程序的网格部署场景
在实现这种场景时可能有必要改变一些原始的假设。比如说,WAS Express 与 WebSphere Application Server Advanced Edition 或 Apache Tomcat 相反,前者不包括 EJB 容器,因此如果网关 servlet 在 WAS Express 中运行的话,如图 7 所示的部署会更容易实现。对原先的情况进行这样的改变实际上能使您的客户获益,因为应用程序的总成本将变得更低。
请记住,这只是实现方法之一。根据应用程序的特征不同,可能存在更好的部署架构模式。最好的解决方案应该在可行性、工作、可用性、管理等方面提供最好的回报。
影响单片式和模块式应用程序的问题同样也会影响到以 servlet 为中心的应用程序的网格启用。此外,还可能出现与应用程序性能有关的问题。
以 servlet 为中心的应用程序在大多数情况下都会在 Web 容器这一层出现性能问题。对网关 servlet 的使用有时可成为糟糕的瓶颈,主要的原因如下(可能还有其他原因):
- servlet 的执行模型,尤其是 servlet 造成的瓶颈可能依赖于 Java Server Page(JSP) 的表示逻辑。
- 连接器框架,如 JNI 等,会造成延迟。在有些 JVM 实现中(比如说我们的),JNI 调用使得 JVM 必须创建指针,以便分配所请求的特定于平台的进程。有时候这些指针会占用大量内存块,JVM 必须不断对其进行刷新,才能避免垃圾收集线程在其尚处于活动状态时将其回收(您不会希望发生这种情况)。这样就在 JVM 中产生了额外的负担,因此 JVM 所运行的 Java 进程会占用更多的 CPU 和内存堆。
这些问题与网格基础设施无关。即便应用程序不在网格中运行,也会引发问题。您需要认识到,一旦应用程序部署到网格中,就必须在新的条件下对应用程序服务器进行调整。应用程序服务器与网格基础设施的交互也可能产生其他一些问题。例如:
- 应用程序服务器和网格基础设施之间实现安全性的开销。由于网格在安全方面的行为不符合常规,同时假定 JNI 调用并不总是会请求验证,结果就是,有时候应用程序必须在每一次进行连接器调用时都向网格基础设施中记录日志。因此运行速度会降低。
- 应用程序服务器和网格基础设施之间的网络延迟,特别是在地理上分散的环境中部署时情况尤为严重。
有时候这些问题会同时出现,使得整个网格启用过程过于复杂、代价过于高昂,以至于不值得。有时候可以考虑一下将应用程序特定于平台的部分作为常规的单片式或模块式应用程序(看哪种情况适合)部署,或是将特定于平台的这部分重新编写为与 J2EE 兼容的组件集,同时使用基于 SOA 的网格基础设施。
回到客户机-服务器的年代,以数据库为中心的应用程序当时是事实上的标准。PowerBuilder、Oracle 2000、PacBase、Progress以及其他一些产品广泛用于创建单片式的、笨重庞大的应用程序,这些程序要求使用私用的语言,而且要具备专业化技巧才能够理解它们。
有些此类产品终于适应新的分布式系统的,并且为我们提供了可支持 Web 的混合产品,现在我们将这些产品称为以数据库为中心的应用程序。有些供应商宣称已经重新涉及了他们的产品,使其成为真正的分布式和 Web 系统,但是对于一些产品,在新的外衣之下,古老的客户机-服务器、单片架构依然没有改变。
这种情况是可以理解的,因为大多数供应商甚至发明了自己的语言,用于描述高度复杂的框架,以实现那时所说的“快速应用程序原型和开发(Rapid Application Prototyping and Development)”。
不论这些产品的技术价值如何,供应商出于一个简单的原因,都希望保留这项技术资本:开发这些产品的过程中投入了大量的金钱。因此,以数据库为中心的应用程序还会保留很长时间。
以数据库为中心的应用程序常见的实现是围绕某种私有的框架进行的。在大多数情况下,这些框架经过打补丁,可以支持 Java 技术、XML、JMS 等其他当前流行的业界标准。图 8 阐述了这种架构最常见的情况。
图 8: 以数据库为中心的应用程序最常见的架构模式
在大多数情况下,应用程序和数据库会绑定到同一个包中,在业务逻辑和数据库操作逻辑之间没有区别。由于这一点,新增的支持模块本质上不能与原始的应用程序进行交互。
以数据库为中心的应用程序的移植场景,通常是通过 Web 容器实现的,如图 9 所示。
图 9: 以数据库为中心的应用程序支持 Web 的典型场景
这种策略非常类似于以 servlet 为中心的应用程序。其中涉及到编写一个网关 servlet,通过把附加的 Java 支持模块用作相关的类,或通过 XML 文件来访问私有的框架。
在以数据库为中心的应用程序中启用网格,最简单的方法就是将它简单地看作一个单片式应用程序。在这种情况下,您需要实现如图 9 所示的部署模式。
但是,以数据库为中心的应用程序有一种很有意思的特征,它也许能提供更有效的方法在网格中部署特定的应用程序。
以数据库为核心的应用程序不仅用数据库来保存数据,同时也用数据库保存配置信息、工作流数据甚至表示元数据。这种对数据库的依赖关系有时是如此紧密,以至于根本不可能将数据库从运行时环境中分离开。在某些情况下,应用程序实际上是在数据库引擎之上运行的。
在数据库运行时就是应用程序运行时的情况下,可以被虚拟化的不是业务逻辑,而是数据。您需要使用数据网格,而不是像前面的场景中那样使用计算网格。
通过在数据网格中将以数据库为中心的应用程序虚拟化,您可以简接实现应用程序运行时的虚拟化,从而虚拟化应用程序本身。应用程序运行所需要的所有数据都可以在网格中的全部节点上访问到,并且不管何时应用程序发生变化,所做的修改也会自动传播出去。
实际上,由于数据在整个网格中传播,所以您对数据库的请求实现了位置独立性。对于发起请求的程序来说,数据好像一直都在本地,而实际上,数据可能位于网格中的任何位置。因此,作为单个实例批处理作业运行的是请求代理调度程序(Java 接口以及胖客户机的驱动程序),而数据则通过网格基础设施实现了虚拟化。
根据业务逻辑编写方式的不同,也许能将数据和业务逻辑一同虚拟化,如图 10 所示。
图 10: 以数据库为中心的应用程序的数据虚拟化场景
请注意,只有当业务逻辑在由数据库引擎触发的进程中运行时,才能将数据和业务逻辑一同虚拟化,大多数私有框架就是这样。
如果反过来,业务逻辑可以又诸如作业提交驱动程序等外部进程触发,也许可以将数据和业务逻辑实际分开,用计算网格处理业务逻辑,用数据网格处理数据库。然而这种方法向部署模型中引入了过多的复杂性,因此在某些情况下可能不可行。
以数据库为中心的应用程序通常具有 CPU 和内存使用率高的特征。这种需求在数据库运行时还要运行应用程序时表现的更为明显。
在某些情况下,由于创建数据网格本身的开销,加上资源饥渴型的数据库运行时环境引发的开销,导致网格部署过程可能不会如预期般进展。在其他情况下,如果可能将数据和应用程序分开,情况就和单片式应用程序类似,因此相同的问题也同样适用。
本文提供的信息应该能够给您足够的信息,您就可以开始考虑为自己的产品启用网格的最好方式了。如果想在特定于平台的应用程序(包括单片式和模块式)和支持 Web 的应用程序(包括以 servlet 为中心的和以 database 为中心的)中启用网格,本文会告诉您该考虑哪些问题。
- 您可以参阅本文在 developerWorks 全球站点上的
英文原文.
- 请参阅 developerWorks 的文章“
为网格设计应用程序 — 学习如何在已有的或新开发的应用程序中启用网格功能”(
developerWorks,2003 年 11 月)
- 红皮书“
Enabling Applications for Grid Computing with Globus -- Chapter 3: Application Architecture Considerations
”提供了相关背景信息。
- 红皮书“
Introduction to Grid Computing with Globus
”提供了介绍性信息。
- 红皮书“
Fundamentals of Grid Computing
”包含了一些基础性的信息。
-
对于能够感知网格的应用程序开发,请参阅“开发网格计算应用程序”
第一部分和
第二部分(
developerWorks,2002 年 11 月,12 月)。
- 请参阅 developerWorks 文章“
Start Here to learn about Grid computing
”,快速了解网格计算(
developerWorks)。
- 有关策略 4 —— 能够感知平台的网格服务,“
用 Globus Toolkit 3.0 编写安全的网格服务”提供了相关安全信息(
developerWorks,2003 年 10 月)。

1996 年 Marlon Machado 作为一名 ISSC 组织(现在是 IBM Global Services)的程序员在乔治亚州亚特兰大加入了 IBM。在那里他从事了各种与分布式架构相关的项目。1998 年,Marlon 加入了位于德州奥斯汀的 SanFrancisco Technology Center。后来,他成为了 IBM Developer Relations 的一名电子商务架构师,他做了高性能、基于 J2EE 的分布式架构和消息驱动的异步网格方面的研究。Marlon 是“Think Grid”的作者和首席教师。“Think Grid”是 IBM Innovation Center 在全球提供的高级开发人员训练营。Marlon 生活在德州奥斯汀和洪都拉斯美丽的加勒比海岸,不过他的大多数时间都周游于世界各地,为 IBM 的ISV 合作伙伴提供协作。可以通过 mmachado@us.ibm.com与他联系。