技术开发 频道

在 WebSphere Application Server 中部署多个共存应用程序并解决相应

【IT168 技术文章】

    在 IBM? WebSphere? Application Server 的单一实例中部署多个共存应用程序在某些环境中具有一定的好处,但在问题隔离和问题确定方面也会产生一些特有的困难。本文阐述保持应用程序共存优势并减少潜在缺陷的影响所需的技术和非常好的实践。

    摘自 IBM WebSphere 开发者技术期刊。

    引言

    在电子商务和 IBM WebSphere Application Server 的初期,用户在各个应用服务器实例中部署单一应用程序的现象非常普遍——他们甚至将多个应用服务器实例集群在一起,专门承载某个单一的应用程序。但是,随着电子商务的普及和发展,越来越多的用户有许多应用程序需要寄宿在 Web 应用服务器上,现在将多个(相对较小)独立应用程序运行在单一应用服务器实例或应用服务器集群的趋势越来越突出。

    此服务器整合或应用程序共存方法有一些优点同时也存在缺点:

    优点

    *成本较低。此方法的主要好处就是其规模上的经济性。用少量的物理服务器和服务器进程承载大量的应用程序通常可以在硬件资源、基础结构、软件成本和系统管理成本方面节约大量的开支。

    *资源共享。在一个服务器实例中,多个应用程序之间共享资源这一概念使得更好地利用资源成为可能。一个应用程序的空闲期可能是另一应用程序的峰值期。当然,这也可能是多个独立服务器共享一个通用的硬件资源池,还可能是在单个应用服务器进程中进一步共享其他资源池(例如,共享内存池、数据库连接池等等)。就其本质而言,这实际上就是随需应变的计算原则。

    缺点

    *问题确定。如果一个服务器崩溃或者开始出现某些异常行为(例如响应时间缓慢、出现错误消息等等),则在同一服务器上同时部署的多个应用程序中,可能很难确定究竟是哪个应用程序造成了此问题,是直接造成的还是间接造成的。事实上,仅关注一个应用程序中的缺陷或错误配置可能是不够的;基础 WebSphere Application Server 运行时中的某个缺陷或错误配置可能以不同的方式影响不同的应用程序——或者可能由于某些特定的应用程序存在而触发,进而影响其他应用程序。在这些情况下,多个应用程序的共存可能使探究问题的根本原因更加困难。

    *问题隔离。由于多个应用程序共享环境中的许多通用资源,源于一个应用程序中的任何问题都可能最终影响在同一服务器上运行的其他应用程序。这些问题可能是从与性能调整相关的细微影响到服务器完全瘫痪,通常需要应用程序部署人员和管理员在处理不同的应用程序时协调他们的活动。

    在本文中,我们将阐述保持应用程序共存优势并减少潜在缺陷的影响所需的技术和非常好的实践。

    故障诊断方法和实践

    对于共存应用程序相关的许多问题,采取的必要方法是在出现问题时排除问题,因此从概述如何排除 WebSphere Application Server 中的问题入手可能对您有所帮助。

    当然,对于特定的问题,有许多详细情况和不同的解决方法。但是,了解两种不同类型的故障诊断方法非常有用,它们几乎适用于各种情况:

    *分析。首先从系统中获取诊断信息(错误消息、跟踪或状态转储),然后尝试分析和理解其含意。如有必要,您可以循环获取更为详细的诊断信息并“逐层深入”地进行分析,直到明显确定导致某个问题的具体原因。这实质上是一种“白盒”方法,它基于您透彻了解所研究系统的内部构造。

   * 隔离。您尝试确定所研究的整个系统中仍存在问题的尽可能小的子集。该子集可能存在于系统的物理组件中(仅在启用应用程序的该部分时才出现此问题),也可能存在于系统的执行流中(仅在尝试执行此特定功能时才出现此问题)。如有必要,可以循环执行此过程以进行测试和消除不确定因素,直至将问题限定到尽可能小的区域,这样可能会非常容易地发现问题的真正原因。与分析方法(分析方法要求尽可能深入了解系统功能的详细信息)相比,此方法只需关注可分组件和流之间的交互,通常不需要详细了解这些组件或流的实际工作方式。这通常称为“黑盒”方法。

    当然,在实际研究问题的整个过程中,通常结合使用这两种方法(例如,先隔离某个组件的问题,然后分析该组件产生的诊断信息),但认识这两种研究方法非常有用,因为每种方法都受各种工具、编码技术、部署策略和管理技术支持。

    尽管在共存应用程序中以及在每服务器一个应用程序中会使用这两种方法,但隔离方法更多地用于共存应用程序中,因为故障诊断的最初目的大多是隔离导致问题的应用程序或主要受某个问题影响的应用程序。例如:

    *在测试服务器中,尝试一次启用或禁用一个应用程序,了解启用哪些应用程序时会出现问题。
    *在不同服务器中临时重新分布应用程序,了解哪个或哪些应用程序会导致问题。
    *尝试一次在一个应用程序中修改 WebSphere Application Server 配置参数(例如 HTTP 缓存、动态缓存等等),了解参数更改如何影响该问题。
 
    这些步骤虽然在某些真实环境中实现时偶尔会有困难,但在其他类似的分析或隔离技术不足以解决问题时,有时是唯一可行的办法。

    我们提供了若干信息资源,通过这些资源可以获得解决各种问题的说明,无论它们是特定于共存应用程序的问题,还是更为一般的问题。请参阅 “权威支持”,获取故障诊断工具和资源的完整列表。

    常用技术和非常好的实践

    下面提供了一些常用技术和非常好的实践,可以帮助您解决或避免与共存应用程序相关的一些问题。尽管有些问题十分普通或显而易见,有些非常复杂,但它们在所有情形中都同样有效和值得考虑:

    1.对与每个应用程序关联的每个对象和资源使用不同的名称
    2.实现简明易懂的应用程序日志和错误消息
    3.仔细评估可能在应用程序之间共享的所有资源和其他对象
    4.执行对每个应用程序的端到端监视
    5.在应用程序之间分离管理功能
    6.始终考虑系统范围的整体情况

    1. 对与每个应用程序关联的每个对象和资源使用不同的名称

    在尝试进行故障诊断的过程中,通常会遇到与问题有关的各种命名对象或资源。一个关键任务是确定这些对象或资源属于哪个应用程序,或者与哪个应用程序关联。因此,在可能情况下,您应该使用一个清楚的命名约定,为与每个应用程序关联的每项内容分配不同的并且易于识别的名称。

    存在许多有用的内容可能与运行的应用服务器中可识别名称关联:

    *用于实现每个应用程序的所有类的 Java™ 包在可能情况下,不同应用程序应使用不同的 Java 包名称。这在许多情况下非常有用,例如:

    当服务器报告一个意外的异常时,您可以检查关联堆栈跟踪的类和方法,来确定哪个应用程序导致了异常或者与异常有关。

    如果服务器崩溃或挂起,通常需要检查从 javacore 中获得的线程转储或系统转储中的一个或多个堆栈跟踪。而且,这些堆栈跟踪中的类和方法可以映射回某个应用程序。

    如果出现内存泄漏,则通过确定致使 Java 堆明显增长的对象的类,并跟踪这些对象,追溯到某个给定的应用程序,通常(而不是始终)可以确定泄漏的根源。

    WebSphere Application Server 运行时使用一个类似的策略帮助区分可能与给定故障情形或缺陷有关的各种内部组件。例如,WebSphere Application Server 系统管理组件的大多数实现类都存在于 com.ibm.ws.sm 之类的包中;WebSphere Application Server 连接管理组件的实现类存在于 com.ibm.ws.j2c 之类的包中,等等。

    *每个应用程序、每个模块、每个 Servlet、属于给定应用程序的每个 EJB 组件的管理名称,以及专门与给定应用程序关联的任何资源。管理名称是在使用 J2EE™ 开发工具或 WebSphere Application Server 管理工具创建应用程序组件或资源时指定的名称。在执行过程中,此名称可能出现在日志和跟踪文件中,通常还用于各种管理和监视工具的命令和显示中。

    *与属于每个应用程序的组件或资源关联的 JNDI 名称。在执行过程中,这些名称可能出现在各种跟踪文件中,在使用确定特殊问题的工具或脚本列出 JNDI 命名空间的内容,以及监视它引用的各种项目的运行状态时,也可以看到这些名称。

    在为每个应用程序中的每个元素分配了定义良好、区别分明的名称后,最后一步是创建并继续维护一个列出这些名称及其关联应用程序的中心文档。然后,在研究某个问题时,系统管理员可以参考此文档,快速确定受影响的文档,并联系可以提供进一步帮助的相应人员。

    2. 实现简明易懂的应用程序日志和错误消息

    反映 WebSphere Application Server 运行时操作的日志通常包含在以下几个定义良好的文件中:SystemOut.log、SystemErr.log、native_stdout.log、native_stderr.log 等等。但是,大多数应用程序还需要生成流式日志记录信息,来帮助监视这些应用程序的正常操作和诊断在应用程序级别遇到的问题。

    为使应用程序日志消息对监视和确定问题尽可能提供帮助,每条消息除了文本消息本身外,还应包括若干关键信息:

    *明确指示是哪个应用程序发出的消息。这可以通过以下方法做到,把来自各个应用程序的日志发送到不同的文件,或者在每个消息前面加上与应用程序相关的标记。WebSphere Application Server 运行时使用的就是这一方法;WebSphere Application Server 发出的每个消息都由一个独特前缀和消息标识符开始,可以直接反映是哪个子系统生成的。IBM 支持人员经常使用此信息来跟踪运行时日志中报告的消息和问题的来源。

    *指示消息发出时间的准确时间戳。这样可以将出现的消息与可能观察到的其他外部事件关联起来(例如,某个负载特别大的期间或系统崩溃),并能够与 WebSphere Application Server 和可能由其他应用程序发出的其他消息关联起来。

    *指示服务器中的哪个线程负责发出此消息。此信息自动随 WebSphere Application Server 运行时发出的所有消息提供;使应用程序日志消息具有相同的信息,可以更容易地将 WebSphere Application Server 报告的一些事件与应用程序报告的事件关联起来,以便跟踪问题的根源。

    *可能情况下,在每个应用程序消息中提供指示,帮助确定在发出消息时应用程序正在处理的特定请求——但并不是永远都这样。这在应用程序处理单个请求过程中发出多个消息时特别有用,这样能够确定哪些消息事实上与同一请求相关,与哪些不相关,从而在系统中跟踪请求的路径。

    经常碰到的问题是,对每个应用程序使用单独的日志文件比较可取,还是将所有应用程序的日志记录合并到单一的输出文件中比较可取。如果所有日志消息都包含上述所有信息,则分不出哪种方法更可取。但是,请注意以下指导原则:

    *使用单一的组合日志文件可以在发生事件时简化收集和扫描反常情况的数据,并简化管理日志文件的增长和轮替。单一日志还可以提供服务器中发生的所有事件时间线的直接视图。如果有必要提取与某个特定应用程序关联的一组事件,则可以通过将所有项与关联该应用程序的特定标记或前缀相匹配做到这一点。

    *相反,使用多个单独的日志文件则在某种程度上较难跟踪、管理和收集不同日志中的所有数据,但它也按每个应用程序提供事件的完整视图。如果有必要确定服务器范围内事件的完整时间线,则可以根据每个日志中与各项关联的时间戳将日志合并在一起。

    实际上,最容易的方法通常是使用 WebSphere Application Server 提供的内置日志记录工具同时写入应用程序日志消息。使用写入 System.out 或 System.err 流的标准 Java 元素,或使用 java.util.logging 包中的方法和 WebSphere Application Server 定义的缺省日志程序,可以很容易地调用这些工具。在这两种情况下,应用程序日志消息将出现在标准的服务器 SystemOut 或 SystemErr 文件中,并且已经使用时间戳和线程标识符预先设定格式(但是,应用程序仍可以在每个消息中提供唯一的应用程序名前缀和适用的请求标识符)。

    另外,每个应用程序可以使用 java.util.logging 工具及其本身自定义的日志程序和处理程序,例如,可以为每个应用程序写入不同输出文件的日志程序和处理程序。在此情况下,应用程序本身负责确保所有日志消息的格式正确(如上所述),并确保正确管理输出文件。

    出于性能原因,无论使用哪种机制,在构建实际日志消息之前,应对应用程序进行编码,首先检查是否启用给定的日志记录级别。创建复杂的日志消息并将其写入只能丢弃该日志消息的日志程序或其他某个工具会带来负面影响,直接影响到每个应用程序请求的执行时间,间接影响到服务器的垃圾收集行为。

    3. 仔细评估可能在应用程序之间共享的所有资源和其他对象

    在简介中已经提到,部署和管理共存应用程序是为了找到一种平衡,既要共享与每个应用程序关联的各种资源,尽可能提高使用效率和性能,又要尽可能减少这种共享,以便于隔离和确定问题。

    尽管共存应用程序的声明目标之一是为了共享多种服务器资源,但有许多与应用程序关联的项在与其他应用程序共享或合并时几乎不能提供什么好处。

    另一方面,应用程序之间越分离,上面提到的许多故障诊断技术(包括一般的分析方面和隔离方法)也越能发挥其作用。例如:

    *能够快速确定某个给定的资源属于某个特定应用程序还是另一个应用程序,便能够将注意力集中于与该资源关联的错误消息分析和行为上。

    *能够启用、禁用或重新配置只影响一个应用程序的给定资源可以极大地方便隔离方法的使用。

    *一般情况下,任何共享项目都会创建一个通道,一个应用程序中的问题通过该通道可能影响另一应用程序的正确行为。例如,应用程序可能争用线程、后台连接等等。那么从这一角度出发,尽可能限制共享还是比较值得的。

    让我们从应用程序共享这一角度,了解一下每个应用服务器中存在的一些主要资源和其他项目。

    线程池 

    在一个典型的 WebSphere Application Server V6.x 服务器中,需要考虑四个主要线程池类型:

   * Web 容器线程池。该池中的每个线程负责处理一个入站 HTTP 请求,并负责执行与该请求关联的所有进程,如执行 Servlet、JSP 和间接从这些 Servlet 或 JSP 调用的任何其他对象(例如位于同一服务器上的 EJB 等等)。除非在非常特殊的配置中,一般在整个服务器范围只有一个 Web 容器线程池在所有应用程序之间共享。

    *ORB 线程池。此线程池中的每个线程负责处理通过 RMI/IIOP 传入的一个入站请求,该请求通常发送到一个 EJB。此同一线程将执行第一个 EJB 和任何其他 EJB 或调用它的其他对象和资源中的代码。在服务器范围内存在一个 ORB 线程池,该服务器上部署的所有应用程序和所有 EJB 共享该线程池。

    *JCA 资源适配器线程池。这些线程池中的每个线程负责处理从服务器中配置的 JCA 资源适配器接收的一个入站消息,并执行关联的消息驱动 Bean (MDB) 和间接从该 MDB 调用的任何其他 EJB 或其他对象中的代码。缺省情况下,创建的所有 JCA 资源适配器都共享一个线程池;不过,可以为每个 JCA 资源适配器明确定义一个不同的线程池。

    *消息侦听器线程池。该池中的每个线程负责处理从侦听器端口接收的入站消息,它通常与一个不使用 JCA 规范的 JMS 提供程序(如 WebSphere MQ 提供程序)关联。对于 JCA,该线程将执行关联 MDB 和间接从该 MDB 接收的任何其他 EJB 或其他对象中的代码。在每个服务器中,对于该服务器中定义并由所有应用程序使用的所有侦听器端口,仅存在一个消息侦听器服务和一个相应的线程池。

    尽管所有这些线程池互不相同,但它们都使用 WebSphere Application Server 中的一个通用池工具实现,因此可以使用一组相同标准的配置参数(最大值、最大值、静止超时和“可增长”标记)控制每个线程池。

    正确管理线程池非常重要,因为线程对于服务器中的内存使用量以及其他低级操作系统资源而言是相当珍贵的资源。因此,我们通常需要保持很少数量的线程,但足够大的线程池可以满足服务器的性能和容量需求。这意味着通常需要对有时关联一个应用程序、有时关联另一应用程序的服务请求启用同一组线程,而不是对每个应用程序都保留一组完全不同的线程。但是,此方法同时会导致严重的性能问题:如果两个应用程序同时需要来自同一线程池的大量线程,它们显然会相互影响,并且您会看到性能下降。在极端情况下,如果一个应用程序在某个特定时段内占用线程池中的大多数或全部线程,则所有其他应用程序可能会“挨饿”,从而导致应用程序的性能非常低甚至会“挂起”。

    假设 WebSphere Application Server 中的大多数线程池是服务器范围的线程池,则这些线程池中的线程实际上通常在所有应用程序之间共享。为最大限度减少应用程序之间的竞争现象(这种竞争现象可能导致应用程序性能低下和供给不足),每个线程池应该足够大,以便能够满足服务器中所有应用程序共同平均稳定状态的需求。当某个应用程序有一个临时的超过平均峰值的负载时,应用程序之间可能会发生竞争。线程池中的线程仅按“先来先服务”原则进行分配;WebSphere Application Server 中没有提供标准机制,为一个应用程序提供优于另一应用程序的优先权。

    不过,为避免应用程序之间发生严重的线程供给不足问题,可以配置一个线程池,允许线程的分配超出最大线程大小。这意味着,当存在大量的活动时,线程池将临时创建其他线程,这样所有应用程序都可以使用所需的线程。不过,在使用此机制时应格外小心:

    *它可以有效地删除允许服务器创建的线程数量的任何上限,因此在极端负载情况下,服务器可能会创建许多线程,以致于无法有效地发挥功能,导致耗尽内存甚至崩溃。

    *在这些条件下创建的其他线程根本不在池中存储;它们在每次处理新请求时创建并在处理完成后销毁。与服务器的正常操作相比,这可能导致性能下降。

    出于这些原因(尽管此机制可以针对线程供给不足提供额外的安全级别),通常更为可取的方法是调整最小和最大池大小来应对大多数情形。另外还需要注意,即使将一个线程池中的线程数配置得非常大或者没有限制,仍可能存在有效地限制服务器能够同时处理多少请求的其他约束,例如,可以接收入站请求的 HTTP 连接数、ORB 连接数或者 JCA 或 JMS 连接数。

    在 WebSphere Application Server 的较新版本中,异步 I/O 工具 (AIO) 还提供一个缓解通信中峰值的附加级别。如果没有足够的线程提供服务,则传入请求(特别是 Web 请求)可以在 AIO 工具中排队,而不是立即被拒绝。这有助于系统在过分负载期间反应比较流畅。不过,对于上述的“可增长线程池”,此解决方案并不是十全十美:在 AIO 工具中排队会带来额外的开销和延迟。这在短期的大量活动时还可以接受,但要获得服务器及其应用程序的稳定操作状态,则不应依赖于此解决方案。AIO 工具中的队列与它向其分派请求的线程池类似,也是服务器范围的,因此也在所有应用程序之间共享。

    最后,对于与 JCA 资源适配器相关联的连接池,事实上可以对不同的资源适配器使用不同的线程池。例如,如果两个应用程序访问不同的 JCA 资源,并因此使用两个不同的资源适配器,则它们可以使用单独的线程池或一个共享的线程池。即使两个应用程序访问同一 JCA 资源,它们也可以为该 JCA 资源定义两个不同的资源适配器,因此能够使用两个不同的线程池。权衡是否使用多个线程池应根据具体情况进行评估,同样需要考虑上述与线程相关的资源使用和可能的线程供给不足问题。

    本部分中的整个讨论内容重点集中在如何使服务器功能尽可能地高效和可靠,并没有讨论如何确定问题。对于涉及服务器中线程研究的大部分问题(挂起、崩溃等等),您解决这些问题的能力在很大程度上取决于这些线程是否在应用程序之间共享。对于这些问题,关键解决技巧一般是获取涉及多种线程的堆栈跟踪,并从查看该堆栈跟踪中涉及的方法和类确定哪个应用程序当前在该线程上执行,并准确地确定该应用程序在执行什么操作。从本质上讲,这取决于您识别有问题的方法和类的能力,而不是识别线程本身。

    JCA 和 JDBC 连接池

    每个 J2C 连接工厂和每个 JDBC 数据源本身都有连接到相应远程系统(企业信息系统或数据库)的连接池。这些连接在使用同一 J2C 连接工厂或 JDBC 数据源的所有应用程序之间共享,它们按“先来先服务”原则从每个池向所有请求应用程序分配。

    与连接相关的注意事项和权衡方式非常类似于前几部分中讨论的与线程和线程池相关的注意事项和权衡方式。每个连接通常使用应用服务器自身中的大量资源,而且也大量使用位于每个连接另一端的后端系统资源。因此,尽可能合用和共享连接一般较为可取。但是,连接与线程类似,也是一种有限的资源,在多个应用程序之间共享连接时也会出现争用和供应不足问题。

    缓解这些问题的技术与线程池类似:基于来自所有应用程序的预期,合并要求认真配置每个共享连接池的大小,或安排每个应用程序使用单独的 J2C 连接工厂或 JDBC 数据源,即使它们最终连接到同一后端系统也应这样做。许多客户“为了安全起见”倾向于分配太多的连接。但是,大多数应用程序都很适合传统的“漏斗线程”(funnel threading) 模型(应用程序比检索数据花费更多的时间去处理数据和构建表示层)。因此,大多数应用程序在 Web 容器中比在 JDBC/JCA 层中需要更多的线程。当然,大多数准确的测量来自模拟生产条件的负载测试,以正确评估这些池的大小。

    对于使用连接到同一后端系统的多个 J2C 连接工厂或 JDBC 数据源而言,必须特别注意的一点是,跨服务器中多个应用程序的单一事务可能最终使用到同一后端系统的多个连接。这种情况不一定不正确,但可能会强制使用开销更大的事务两阶段提交协作。当从一个或多个应用程序分配的所有连接来自一个池时,可以根据需要将 WebSphere Application Server 连接管理子系统配置为启用 J2EE 可共享连接工具,该工具不能跨多个独立连接池使用。

    在使用可共享连接时,即使一个给定的事务请求多个到同一后端系统的连接,WebSphere Application Server 将确保事务实际上始终得到同一(单一)连接的副本。对于某些应用程序的使用模式,这明显可以减少所使用连接的总数量,从而减少潜在的争用和供给不足问题。但另一方面,要知道可共享连接在其他程序使用模式中还会带来连接争用加剧的风险。由于系统预先不知道某个给定的事务在完成之前是否多次请求同一连接,因此该连接在整个事务过程中保持分配给该事务,即使该应用程序表现为明显释放了该连接也如此。所以,使用可共享连接工具可以减少每个事务所使用连接的总数,但可能增加每个连接使用的时间间隔,因此导致无法将这些连接分配到其他应用程序或事务。总而言之,是否使用可共享连接实际上将导致总体减少或者增加争用情况,因为连接在很大程度上取决于每个特定应用程序的特定连接使用模式。

    而且还要知道,WebSphere Application Server V6.x 还提供了一个用于定义应用程序范围资源的工具,从开始关联和部署单一应用程序时就定义这些资源。在此情况下,应用程序之间的任何共享问题显然可以解决。这可以大大简化许多资源的管理。

    通用库和其他通用代码

    有时,多个应用程序使用同一个打包为 JAR 文件(对于 Java 代码)或本机库(对于通过 JNI 访问的代码)的实用程序库。它们可以嵌入到应用程序的 EAR 文件中(在此情况下,将成为该应用程序的专用库),也可以通过 WebSphere Application Server 中的共享库对象对它们进行管理。共享库既可以在服务器级别进行配置(在此情况下,该库的单一副本可以访问该服务器上的所有应用程序),也可以在应用程序或模块级别进行配置(在此情况下,引用共享库的每个应用程序或模块都通过不同的 Java 类加载器获得自己的库副本。)

    类似地,在其他一些情况下,Web 或 EJB 模块提供的一些通用功能有时可能用于多个应用程序。这样我们就有这样一个选择:是在每个请求应用程序中部署通用模块的单独副本,还是安排所有应用程序远程访问物理部署在单个应用程序(这可能是一个独立的应用程序,它的唯一目的就是承载通用模块,为服务器上的所有其他应用程序提供方便)中的通用模块的单一副本。

    这提出一个重要的权衡问题。您如果倾向于使用大多数通用代码组件的单一副本,则必须知道许多通用组件(代码和数据)使用的内存通常很多,所以使用同一组件的多个副本通常会增加服务器的内存使用量。但是,在另一方面,使用一个通用组件的多个独立副本在某些情况下可以防止某个故障影响到多个应用程序。大多数通用组件不只是包含代码,还包含状态信息,形式有 Java 静态变量、独立对象和本机内存缓冲区以及由该通用组件间接引用的任何其他资源。如果任何一种状态信息遭到破坏(通常由于在实现组件中的缺陷或不可预知的环境因素),则共享该组件同一副本的所有应用程序多数情况下都会受到影响。另外,如果通用组件中的代码包含瓶颈(例如许多并行应用程序请求必须通过单一监视器或关键节),则共享同一副本的所有应用程序将会相互竞争,从而扩大瓶颈的影响。当然,在需要某个特定的应用程序时,使用多个独立副本可以更容易地将组件替换为不同的实现或版本,而不会影响其他组件的稳定性。

    在实践中,应该对每个应用程序、通用库或模块逐一进行权衡和评估。

    类加载器

    WebSphere Application Server 运行时创建了一个 Java 类加载器的复杂层次结构,以协调每个程序的各种 Web 模块、EJB 模块和依赖库中所有 Java 类的负载。从共享或隔离应用服务器 JVM 中加载的各种类的角度而言,类加载器非常重要。由不同类加载器加载的两个类严格限制相互之间的可视性,因此可以限制不必要的相互干扰。而且,如果类由不同的类加载器加载,还可以加载同一类的多个副本(同一实现或不同实现)。前面管理通用库和其他通用代码部分提供了在共享与类关联对象的优缺点方面需要进一步考虑的因素。

    完整讨论各种类加载器策略的全部细节超出了本文的讨论范围,但从共存应用程序角度而言,我们应知道直接影响多个应用程序之间共享的类加载策略的一个特定方面:在每个应用服务器的全局配置中,您必须选择一个特定的服务器范围的类加载器策略(“单个”或“多个”)。当“单个”服务器类加载器策略在起作用时,将使用单个类加载器为服务器上部署的所有应用程序加载大多数类。相反,当“多个”服务器类加载器策略在起作用时,将对每个应用程序使用一个单独的类加载器。

    因此,要在不同应用程序中的类之间执行任何类型的分离(包括上述共享库和应用程序之间任何其他可能的交互),您需要将服务器类加载器策略设置为“多个”。根据一般经验,除非特定的应用程序或环境存在严格约束,使用“多个”服务器类加载器策略通常较为可取。

    JVM 堆内存

    除非在某些非常特定的用于实时处理的新 JVM 中,一般在每个服务器中存在一个 JVM 堆,该堆包含所有应用程序和 WebSphere Application Server 运行时组件分配的所有 Java 对象的所有实例。因此,此堆从定义上讲是在所有应用程序之间共享的,并且一个应用程序分配过多的对象很容易影响其他应用程序,结果可能是在堆上没有留下可供其他应用程序正确工作的足够空间,或者导致频繁的垃圾收集。

    标准 WebSphere Application Server JVM 中没有限制每个应用程序访问堆的内在机制。因此,对于使用 JVM 堆资源而言,您的策略依据必须是确保每个应用程序行为良好。应认真测试每个应用程序,以确保它不存在内存泄漏问题。

    如果确实存在错误并且造成堆超载,则便于分析堆内容和确定应用程序责任的非常好的策略应依赖于其实例占用堆空间的特定于应用程序的类名称。如果每个应用程序都使用不同的类,则更容易找出问题的根源。

   应用程序部署构件

    这些构件包括 EAR 文件、WAR 文件、Web 和 EJB 模块等等。除非在非常特殊的情况下,通常没有理由将逻辑上不同的多个应用程序合并到单一部署构件,并且对服务器资源的使用和性能没有太大的好处。每个应用程序应有自己的 EAR 文件和在该 EAR 文件中有自己的模块集。这样,您可以独立地部署、更新、管理和监视每个应用程序。还能让您独立地启动和停止每个应用程序,这在尝试隔离问题根源时非常方便。

    与每个 Web 应用程序关联的虚拟主机

    在应用程序之间共享虚拟主机时很少甚至不会节省什么资源(除了对 HTTP 连接可以使用较少的端口)。另一方面,向每个应用程序分配不同的虚拟主机和一个易于识别并且互不相同的上下文根,可以非常方便地在系统中的跟踪文件中跟踪 Web 请求流,并将其与给定的应用程序相匹配。因此,如果承载各种应用程序的网站组织允许,对每个应用程序分配不同的虚拟主机不失为一个好主意。

    消息传递资源

    这包括诸如服务集成总线、JMS 提供程序、队列、主题、目的地等资源。此类资源是在服务器范围分配的(可能连接到同样是服务器范围的某些其他资源,如 JMS 提供程序),并且可以由服务器中的一个或若干应用程序自由访问。

    对于此类资源,一般很少关注争用和供应不足问题,但与服务器中任何其他类型的对象类似,它们确实消耗一定的内存量,因此可能需要决定是对某些实体创建单一共享副本可取,还是创建多个独立副本可取。

    为每个应用程序定义单独的消息传递资源可能特别有益,这样可以单独地启动、停止和监视每个应用程序,从而便于进行各种故障诊断任务。

    4. 执行对每个应用程序的端到端监视

    认真计划应用程序包装和消息传递是它为监视环境带来的最大好处。监视工具(如 IBM Tivoli® ITCAM 工具套件)可以报告整个系统的运行状态,并能够显示环境中各个元素的性能。良好实施的命名约定可以让管理员和系统团队轻松地识别问题组件及其拥有者。

    使用 Tivoli Performance Viewer 确定基本问题

    随 WebSphere Application Server 提供的 Tivoli Performance Viewer 支持从应用服务器显示 PMI 的基本数据。管理员可以使用 Tivoli Performance Viewer 查看内部 WebSphere Application Server 资源的统计信息,例如 JDBC 连接池、Web 容器线程以及由应用服务器控制并且无法由更多传统系统工具访问的其他资源。

    Tivoli Performance Viewer 显示的度量范围从轻量测量(如池活动)到更精细的测量(如 EJB 方法级响应时间)。虽然并不是所有测量都适用于某个大容量的生产应用程序,但它们确实提供了针对应用程序行为的有用见解,特别是在测试环境中更是如此。

    例如,在测试环境中,测试员或管理员可以启用方法级度量来显示被测试应用程序(或应用程序组)的组件响应时间。如果 Servlet、JSP 和 EJB 都使用一致的命名标准,则管理员可以方便地将具有较长响应时间的元素与某个特定所有者匹配。

    复杂监视

    此相同的一致性命名原则还通过更复杂的工具集提供了一些好处。用于 WebSphere 的 Tivoli ITCAM 可让您在较高级别监视应用程序,然后逐层深入进行更详细的问题确定分析。管理员利用此工具的详细分析功能可以查看详细的流程和度量,包括泄漏检测分析,指出造成泄漏的代码行。显然,在此分析级别上,良好的类命名方案支持对由多个应用程序共享的环境进行调试和问题报告。此工具还支持按类名称过滤监视器。例如,在详细分析过程中,您可能希望通过将度量集中于属于一个特定应用程序的类,简化数据收集和减少开销。而且,强制的包命名方案使该操作更加容易。

    企业度量

    WebSphere Application Server 还支持应用程序响应度量 (ARM) 标准。WebSphere Application Server 的许多内部元素(Web 容器、EJB 容器及其他元素)都进行 ARM 检测。诸如用于响应时间跟踪的 ITCAM 之类的工具在事务到达 HTTP 服务器、通过应用服务器甚至进入数据库层时,可以报告该事务的各种组件的响应时间。一般情况下,会定期对触发的综合事务进行 ARM 检测,以减少测量开销。

    您可以使用 ARM 标准检测代码来增加报告度量的粒度。IBM 通过 Build To Manage (BTM) Toolkits 为此提供了一个方便的解决方案,目前在 developerWorks 上提供。BTM 提供了一个简单的 Eclipse 接口,可以让用户为检测选择类。BTM 然后为这些类自动生成 ARM 代码(图 1)。而且,通过按强命名标准区分类,ARM 可帮助您更好地指出问题类及其拥有者。

图 1. Build To Manage 检测示例
 

    5. 在应用程序之间分离管理功能

    在具有多个区别相当大的应用程序环境中(可能由不同的团队开发和维护),通常需要将管理功能分离开,这样每个团队都可以管理自己应用程序的开发和操作,而无需访问其他应用程序。此类分离仅限于多个应用程序共存于单一应用服务器上这一有限配置级别。实际上存在许多服务器范围的资源,这些资源必须由至少对整个服务器有管理访问权的人员进行管理。不过,可以分离一些管理功能,例如,以每应用程序为基础启动/停止/配置某个应用程序。在单一服务器环境中这样做与在传统的多服务器环境上这样做实际在技术上是相同的:

    为每个最常用的管理操作创建多个 wsadmin 脚本。确保将每个脚本配置为能够访问足够的凭据,以便可以在服务器上操作,但将脚本本身的访问权限制在每个适当的用户组。此方法虽然比较复杂,但对 WebSphere Application Server 的所有当前版本都适用。

    另外,WebSphere Application Server V6.1 还包括一项名为细粒度管理安全性的功能,通过该功能可以为每个应用程序定义不同的权限组,并仅将该权限组的访问权授予 WebSphere Application Server 身份验证域中的特定用户。请注意,此工具仅在通过 wsadmin 工具进行访问时适用。为有效使用管理控制台,用户需要对整个系统有广泛的访问权限。

    6. 始终考虑系统范围的整体情况

    最后,尽管本文大部分内容都在集中讨论如何确定和隔离属于某个特定应用程序的信息,但是有关故障诊断的文章如果不提示始终要从全局角度考虑故障诊断则是不完整的。即使在非常好的设计的系统中,在应用程序之间、服务器之间以及每个服务器和各种外部服务或资源之间也可能始终存在一些无法预料的交互。因此,优秀的故障诊断人员在尝试寻找问题的原因以及了解系统行为的同时始终会兼顾全局情况。

    结束语

    在单一的 WebSphere Application Server 实例中部署多个共存应用程序可以在某些环境中提供非常有价值的好处,但在隔离问题和确定问题方面也可能产生一些特有的困难。在大多数情况下,通过认真设计和管理服务器中每种资源类型的共享方式,通过很好地跟踪每个与应用程序相关的对象或资源的标识,并通过对系统监视和故障诊断使用良好的原则和可靠的技术,可以有效地排除这些困难。

0
相关文章