Free Citizen

Tuesday, January 11, 2005

《J2EE性能测试》说明

《J2EE性能测试》看起来是本好书。没准以后去买一本。

J2EE 性能测试

每个J2EE应用程序都是真正独一无二的。这使得从一个应用程序推断另一个应用程序的性能非常困难,甚至不可能,而不管它们的功能是何其相似。为了掌握你自己应用程序的性能,你必须按照自己的性能定义亲自测试它。

就性能而言,我们经常提到的一些问题有:
• 应用程序的运行有多快?
• 它将适用于多大的规模?
• 应用程序服务器的性能是什么?

就 像开篇所指出的那样没有明确的答案,我们也不能提供一个解决所有与性能有关的问题的清单。但是,我们认为我们所能做的是提供一个工具和一种性能测试方 法,让J2EE开发人员针对他们自己的应用程序,获取可靠的有意义的性能数据。本书描述了这两个方面以及我们所承担的性能研究与研究结果。这些结果只是用 来强调文章开始所说情况的真实性。
我们的测试方法提供了一个清晰的框架。该框架描述了如何定义性能测度和目标、需要采取的测试、收集数据的方法,以及最终真正执行测试的方式。该方法非常简单、灵活,而且能够适应于任何以其他语言写的应用程序。
我 们选择了使用一个称为The Grinder的负载生成/数据收集工具(随同相关的软件)来说明该方法的优点。The Grinder是一个基于Java的工具,可以在公共域获得。尽管在商业和公共领域都有各种各样的负载生成工具,但是作者直接参与了The Grinder的开发,所以它成了一个顺理成章的选择。然而,这并不意味着你必须使用该软件。相反,该测试方法不附属于任何特定的工具,因此可以自由使用 你感觉最舒适的工具。
虽然本书的性能测试是使用BEA WebLogic Server进行的,但是介绍的技术可以用于任何J2EE应用程序和任何J2EE兼容的应用程序服务器。可供下载的代码中的某些组件(如配置文件)是专用 于WebLogic Server的,但是改编该代码并在你自己的环境中运行测试是一件比较简单的事情。此外,我们所做的某些环境优化将利用该服务器的专有特性,但是其他应用 程序服务器也很可能提供了类似的优化。
在本简介的剩余部分,我们将尝试确切地说明我们的方法和工具所能达到的目标,并指出它们与其他可用工具和方法的关系。我们还将为本书的剩余部分提供一个清晰的简要介绍。

J2EE性能测试
我们的方法和工具可以用于以下两个基本情况:
• 性能测试一个完整的应用程序。
• 性能设计——分析J2EE API不同方面的性能代价,以及某种设计决策对总体性能的影响。
在 第一种情况下,我们将应用程序看做一个黑盒子,使用该方法和The Grinder以测试该应用程序在不同负载下的性能。我们可以调查应用程序产生的每个请求的性能(简单的JSP请求、调用整个实体bean的会话 bean、与数据库交互以便更新记录的实体bean,等等)。我们能够分析数据,发现限制性的请求,并确定改善性能的机会。
虽然以上这些是有帮助 的,但我们建议在开发周期中尽可能早地进行测试。这样可以使用该方法以及从中获得的数据来帮助你进行性能设计,而不是“事后”的性能 测试。每个小的组成应用程序的子系统都将直接影响整个性能。通过早期测试,将能够在设计中使用最佳规划惯例,并回答将这些惯例应用于你惟一的应用程序时的 一些基本问题,比如“应该使用哪个J2EE API?”、“是否应该避免使用静态会话bean?”、“实体bean是否太慢?”、“哪种J2EE设计模式适合于我的情况?”,等等。
本书用了 一章介绍黑盒应用程序性能测试,用了五章探讨与流行的J2EE API(Servlet、EJB和JMS)的使用有关的共同问题及其设计选择。我们将展示如何评估选择对象,并利用我们所提出的性能结果,设置一个一般的 相对性能期望值。然而,最终的结论是你不能想当然地假定我们的结果将适合于你的环境,你必须获取自己的性能数据。

什么是性能
为了 理解自己的应用程序的性能,你必须按照自己的性能定义亲自测试它。这是非常重要的一点。我们经常被问到的常见问题之一是:“我的应用程序在你的服务器 上的性能将怎么样(在我们的实例中,服务器就是WebLogic Server)?”这通常指望我们提供一个有魔力的数字,描绘整个性能。实际上,我们的回答是性能依赖于应用程序以及性能的确切含义。

J2EE 是一组广泛的API,甚至一个相对简单的J2EE应用程序都可以以多种方式编写。例如,让我们考虑一个简单的数据库访问应用程序。从前端开始,你 可以有一组JSP和servlet处理与终端用户或客户端的通信。该前端使用JDBC可以直接和数据库通信。然而,开发人员可以选择让该前端调用一个无状 态的会话bean。然后该无状态的会话bean使用JDBC API与数据库通信,或者是将该访问委托给一个实体bean。实体bean可以使用容器管理的持久性(Container-Managed Persistence,CMP)或者是Bean管理的持久性(Bean-Managed Persistence,BMP),等等。

甚 至在使用同一个API集合的时候,一个开发人员也可能以完全不同于别人的方式使用它们。而且我们知道在开发人员之间其代码的质量存在巨大的差别。即使代 码是同样的,输入数据也很可能不同。这将不可避免地造成不同的使用模式,进而产生不同的性能结果。就像我们开始所说的那样,每个应用程序都是惟一的,获取 清晰的真实的有关其性能的答案的惟一方法是,在你自己的特定环境中亲自测试它。
这把我们带回到实际的性能定义。在有些情况下,好的性能意味着能够支持巨大的用户数量;在另外一些情况下,用户负载可能比较小,好的性能可能仅仅是运行得尽可能快。为了更深入地分析,我们可以将开发的应用程序分成两个基本的类别:
• 交互式的,即当终端用户与应用程序同步交互时。
• 批处理或后端应用程序,即当不需要直接与终端用户交互时。

交互式应用程序
对 于交互式应用程序,性能一般是通过大小和规划问题的容量来定义,例如应用程序能够处理的同时发生的用户数量。或者是更具体地讲,就是能够支持指定的用户 数,而同时满足一些关键的参数。这些“必需的参数”可能包括特定的部署硬件,或者是最大响应时间(应用程序完成任何来自终端用户给定请求所花费的时间)。
从 终端用户的角度看,关键的性能属性是响应时间。在我们的经验中,用户倾向于通过感觉到的响应速度来测量应用程序的性能。非常有趣的是,我们发现在决定用 户对应用程序质量的感知方面,真正的功能或者是易于使用的趋势所产生的影响要比响应时间小。我们将响应时间看做表达应用程序性能必需的一个基本的关键统计 量。
响应时间直接受到同时与应用程序交互的用户数的影响。因此在处理响应时间时,必须考虑同时发生的用户数量。从操作员的角度看,他们需要一些信 息,帮助他们 按照容量规划目标确定应用程序的大小。他们主要想知道在硬件资源被耗尽之前,应用程序能够处理的用户数量。随着用户负载的增加,测试应该指出工作繁忙的硬 件系统组件。这可以反过来告知如何在应用程序服务器、数据库服务器和网络之间最佳地分割硬件预算资源。此外,该信息还能够帮助确定最优的部署配置。前端 (servlet和JSP)可以运行在一个应用程序服务器上,而事务逻辑(EJB、JMS队列等等)运行在另一个服务器上。这些实例可能运行在同一台计算 机上或者是分开的计算机上,所有计算机都可以使用相同或者是不同的操作系统。在这个类别中经常问到的问题就是可以在多处理器计算机中使用的应用程序服务器 的实例数量。
基于这种讨论,我们可以容易地推断需要一个测度来反映这两个度量标准:同时发生的用户数量和响应时间。实际上,在刚开始开发我们的方法时,我们就曾设法发明一种新的统计量,以一种简单的方式表达该信息,但是这被证明是徒劳的。
作为替代,我们的方法采用了简洁短小的性能陈述,可方便地传达应用程序的能力与限制(limit)。例如,如果最大响应时间是1000毫秒,那么我们可以达成如下陈述:
该应用程序能够以1000毫秒的最大响应时间处理750个同时发生的活跃用户;峰值时刻有800用户,响应时间下降7%。
我们强烈地感觉到类似这样的简单陈述,正确地传达了整个被测应用程序的性能和界限情况,同时最小化了可能的误解与混淆。该陈述还描述了响应时间被超过时观察到的行为。在进行性能规划时,这是非常有价值的信息。

后端应用程序
当应用程序的主要接口是面向用户的时,基于响应时间和用户数的性能陈述是有意义的。然而,当应用程序具有与另一个系统的接口时,例如一个需要处理的JMS消息队列,这样的度量标准可能就不太适用。
当 我们详细研究批处理或后端应用程序的需求时,我们发现最有用的、使用得最普遍的性能统计量是吞吐量。表达吞吐量性能最流行的方式之一是每秒的事务处理 (Transactions Per Second,TPS)。但是如果没有完全准确地理解其含义以及所测量的内容,那么该度量标准可能导致一些问题。
一 个常见的误解是TPS中的T真正代表的含义。什么是事务处理?人们通常不能理解在他们的上下文环境中事务处理是什么。每个人都认为他们在讨论同一件事 情,而在实践时却不是。我们就遇到两组开发人员开发同一个项目却使用不同的“事务处理”定义。一个组将其定义为单个查询,而另一组则将其定义为一组特定的 查询。有时候,操作组将以完全不同的方式定义它!这当然会导致混淆,结果可能是应用程序按照某个组的定义满足性能需求,而不是另一个组的需求。
当 分析J2EE API时,我们在本书中广泛地使用了吞吐量度量标准。我们认为它为系统吞吐量提供了一个有用的比较测度,前提是清楚地说明了上下文。在研究servlet 时,我们定义事务处理为一个请求——因此吞吐量是servlet在一个设定的时间周期内(一秒)执行的同样请求的数量。当分析JMS时,吞吐量就是消息 (message),依次类推。在存在清晰的事务处理概念的地方,并且测试条件是不变的,TPS能够就某些代码修改是否改善或降低应用程序模块的相对性能 提供有帮助的指导。
然而,我们必须提醒读者有关该度量标准的几个注意事项。吞吐量不是一个速度测度,它差不多是一个容量(capacity)测度 ——这是一个常见的误解。它 不是一个像响应时间那样原始的清晰的度量标准。测试条件的小改变可能对获取的吞吐量数值产生巨大影响——而且它并不一定意味着应用程序执行得更好或更糟。
吞 吐量并不总是提供应用程序性能的完整描述。一个应用程序可能执行10000 TPS,但是终端用户的响应时间是什么?用户是否需要等20分钟才能得到一个响应,或者仅仅是300毫秒?这样,为了提供完整的性能描述,吞吐量通常与其 他测度一起使用,特别是在测试交互式应用程序的时候。
最后,该度量标准本身并不传达计算机上负载的情况。也就是说,它没有告诉我们该计算机的容量是否100%地使用,还是仅仅使用了20%。我们认为这样的测度应该与吞吐量一起使用。

上下文测试方法
本 书标题为“J2EE性能测试”,看起来非常直观,但实际上这是非常仔细选择的结果,以便最好地反映其内容的真正意图与焦点。为了理解这一说法,你只需要 考虑一下经常使用的那些与应用程序软件性能相关的诸多表达就可以,如测试、 基准测试(benchmarking)、轮廓(profiling)和调整(tuning)等等,此处只列举少数几个。尽管它们似乎经常交替使用,但是这 些术语中的每一个都有明确的含义。某种程度上很容易理解为什么会这样,因为每个人对在任何特定的时刻哪方面的性能与他的工作最相关都有他自己的看法。
在本书中,性能测试的含义是使用一种规定的方法收集你自己的应用程序的性能统计数字。但是,了解其他这类术语的含义并讨论在这些领域中如何使用本书的方法是有帮助的:
• 基准测试(Benchmarking)——一般来讲,基准测试是在各种不同的环境和工作负载下记录应用程序性能的过程。
• 轮廓(Profiling)——这涉及到精确地调查应用程序将大部分计算周期花费在什么地方,以及应用程序如何高效地使用系统资源。
• 调整(Tuning)——测试、基准测试和轮廓都反馈给调整过程,后者是优化应用程序和环境获取最大性能的过程。

基准测试
我 们的工具集和方法可以用来基准测试一个应用程序。就像前面所描述的那样,在开发应用程序的时候,你可能在一种配置中测试它,然后再调换一个组件重新测 试,或者是进行一种环境调整(比如增加JVM的堆栈空间)然后再测试。这就是基本的基准测试过程。事实上,我曾经考虑将本书称为“J2EE性能基准测 试”,但是我们最终决定放弃该术语,以免将本书要着手达到的目标与行业基准测试相混淆,比如ECperf (http://java.sun.com/j2ee/ecperf/)和TPC-W (http://www.tpc.org/)。
行业基准测试的问题是,它们是非常明确的应用程序,试图测量类似于J2EE那样的产品或基础结构的一般特性。而我们强调不能从一个应用程序推断另一个应用程序的性能结果,不管它们是多么的相似。
例 如,ECperf是官方的J2EE基准测试。那是一个复杂的EJB应用程序,为测量J2EE应用程序服务器的性能和伸缩性而设计的。它主要面对的是 J2EE应用程序服务器供应商(如BEA Systems、IBM和iPlanet),以便他们能够用它来现实他们产品的性能。
我们在附录C中为 感兴趣的读者提供了更全面的关于我们的工具和方法与ECperf的比较。其他基准测试套件,例如TPC-W(Transaction Processing Performance Council - Web e-Commerce,事务处理性能委员会——Web e-Commerce分会),测量与Web服务器吞吐量相关的性能。这对于开发应用程序服务器的工程师可能有帮助,并且可能在销售该服务器的时候用得着, 这有点像数据库公式使用TPC事务处理基准那样。最终它可能有助于购买的决策过程,但是一般不能提供对J2EE性能状态的合理意见。
此外,我们强调不应使用任何一般的基准测试结果来猜测你的应用程序的性能状态。组成应用程序的每个子系统都对其性能有直接影响,为了真正了解其性能你必须测试你的应用程序。

轮廓
就 像上面描述的那样,轮廓在本质上是对应用程序正在进行的工作及其如何使用系统资源的深入分析。主要目标是突出系统中潜在的性能瓶颈。我们的测试方法将使 你能够确定应用程序中具体的限制性质的区域。然后可以使用一个免费赠送的轮廓工具详细分析这些区域。在本书中除了The Grinder外,我们还使用了各种各样的工具来研究系统的每个组成部分:
• 数据库——在Oracle数据库中,我们使用轮廓工具SQL_TRACE和TKPROF。两者都是作为标准提供的,是输出应用程序执行的SQL语句以及该SQL的执行方式。
• WebLogic服务器——我们使用WebLogic控制台详细查看WLS的内部情况。
• J2EE应用程序——我们利用一个称为Introscope的工具,该工具来自Wily Technology(http://www.wilytech.com),用来帮助准确查明应用程序中组件级的瓶颈。另一个流行的J2EE应用程序轮廓 工具是JProbe(http://www.sitraka.com/software/jprobe/)。

调整
一个典型的 J2EE应用程序将建立在一个应用程序服务器的基础上,但这不是组成应用程序惟一的子系统。此外,还有数据库、Java虚拟机(Java Virtual Machines,JVM)、操作系统、TCP/IP堆栈、Web服务器、网络、路由器和现行的计算机硬件。所有这些子系统都有调节器或参数,可以调整它 们以最大化应用程序的性能。在本书中我们将使用利用我们的方法初步测试的结果来调整环境的各个方面,比如JVM和WebLogic服务器本身。这给予我们 最适宜的环境,以便运行正规的性能测试。

在我们根据测试测度和相关的轮廓提供应用程序级的性能改善建议时,我们并没有承担任何实际的调整工作,因为那不是本书的焦点所在。

第1章 测试方法
方法概述
建立性能标准
模拟应用程序的使用
采样方法
性能统计数字
性能测试
小结

第2章 The Grinder
获取The Grinder的地方
The Grinder概况
入门
使用The Grinder控制台
使用HTTP插件
编写Grinder插件
定时
使用TCP Sniffer创建测试脚本
提示
The Grinder的历史和未来
小结

第3章 应用程序实例研究
为Java Pet Store选择一个JVM
e-Pizza应用程序
改善E-Pizza的性能
使用WebLogic群的性能测试
结论

第4章 HTTP和servlet
概述
针对性能的servlet设计
测试servlet和测试脚本
测试环境
设置并运行测试
预备测试
测试计划
servlet聚类
小结

第5章 EJB设计模式
设计模式
通过测试改善EJB设计
应用程序情境(Scenario)
测试脚本
测试配置
设置并运行测试
测试会话外观模式
测试值对象模式
测试数据访问对象模式
EJB部署配置测试策略
小结

第6章 JMS点到点消息收发
JMS点到点消息收发概述
性能测度
JMS PTP性能问题
测试配置
The Grinder插件和测试脚本
设置并运行测试
扇出测试
JMS扇出结构的总体结论
多队列
结论

第7章 JMS出版/订阅消息收发
Pub/Sub消息收发概况
应用程序体系结构
The Grinder插件和测试脚本
证券报价机应用程序
结论
航线座位安排例子

小结
附录A The Grinder参考
附录B 硬件和软件
附录C ECperf和本书测试方法的比较