优化大师 Jack Shirazi 和 Kirk Pepperdine 分别是 JavaPerformanceTuning.com 的董事和首席技术官,他们从事全球 Internet 上的性能问题讨论。在 TheServerSide.com 留言板上最近提出了一些关于压力javascript:;" onClick="javascript:tagshow(event, '%B2%E2%CA%D4');" target="_self">测试和负载测试的问题。Jack 和 Kirk 详细探讨了这一主题,并讨论了正确的工具如何导致结果产生巨大的差别。
TheServerSide.com 讨论板通常是相当活跃的,所以这个月我们驻步于此以了解在性能世界中发生了什么事情。讨论板的名字就是 TheServerSide,所以在这里讨论的性能集中于 J2EE 系统是很正常的。当然,这是一个相当广泛的题目,因为它包含了 Java 平台中的几乎所有内容——连 J2ME 系统常常也是 J2EE 系统的客户机,所以有时您甚至可以遇到关于优化 J2ME 系统的问题。
压力测试和负载测试
在性能列表中最常问的问题是:“是否有一种工具可以帮助我对 J2EE 应用程序进行压力测试?” 在回答这个问题之前,让我们问一问自己:压力测试是什么,为什么这些开发人员需要它?(我相信你们中相当一部分人曾经遇到一定要在昨天完成测试这种让您感到压力的情况,但是我们在这里说的不是这个)。压力测试是为了发现在什么条件下您的应用程序的性能会变得不可接受。这通过改变应用程序的输入以对应用程序施加越来越大的负载并测量在这些不同的输入时性能的改变来实现的。这种操作也称为负载测试,但是负载测试通常描述一种特定类型的压力测试——增加用户数量以对应用程序进行压力测试。
对应用程序进行压力测试最简单的方法是手工改变输入(客户机数量、需求大小、请求的频率、请求的混合程度,等等)并描绘性能的变化。对于一些应用程序,您需要做的就是这些。但是如果有许多输入,或者需要在大的范围内改变输入,那么就可能需要一个自动化的工具。另外,在手工测试中,如果想在进行一些改变后重新测试应用程序,可能很难精确地重复一组测试。如果是让多个用户测试您的应用程序,那么几乎不可能一致性地运行手工测试,除非您有很多失业的朋友,否则扩大测试应用程序的用户数量是非常困难的。
没有一刀切的方案
不幸的是,没有一种通用的压力测试工具,因为每一个应用程序所接受的输入以及对它们进行处理的方式都是不同的。但是对于许多 J2EE 应用程序来说,从客户机到达服务器的通信使用的是 HTTP 协议。幸运的是,有许多负载测试工具可以以一种可控制和重复的方式模拟 HTTP 上的用户活动。它们包括免费工具如 Apache JMeter、The Grinder 以及 PushToText,和相当昂贵的工具如 Mercury');" target="_self">Mercury Astraload。一般来说一分钱一分货——工具越贵,它能做的事情就越多。为了了解它们的差别,我们首先来看最基本的负载测试工具能做些什么。
如果您想构建自己的负载测试工具,那么您会首先编写一个对每一个模拟客户机运行一个线程的程序。每一个线程需要与服务器通信,可能使用 java.net.URL 类。这种方法使您得到基本的 HTTP 客户机模拟,它可以执行 GET 和 PUT。每个线程需要做的就是发送 HTTP 请求、收集回复、等待一些时间(模拟“考虑时间”),再重复。这一组行动可以相当容易地抽象到一个单独的配置文件中。很快,您就得到一个基本的负载测试工具。您可能需要增加一些配置选项以确定运行多少个线程(模拟的客户机)以及它们是同时开始还是慢慢增加负载。当然,您需要对与服务器的交互计时,因为这是您要测试的核心内容。
如果这么简单……
那么,对于处理扩展的交互(即一个请求取决于上一个请求的结果)如何呢?对于处理 cookies 如何呢?cookies 对于许多面向会话的 J2EE 系统是必不可少的。改变数据输入呢?如果 J2EE 应用程序客户机需要处理一些 JavaScript 以进入下一次通信呢?在收集了响应时间数据后,如何对它进行分析?其他类型的监视,如 CPU 时间、网络使用、堆大小、分页活动或者数据库活动呢?
像这样和其他的功能,如用于记录浏览器会话并将它们加入到测试脚本中的工具,是高端负载测试工具与基本工具的差别所在。如何为自己选择正确的工具呢?当然,这取决于您的需要、您的计划和您的预算。最重要的是,您需要使用可以正确地模拟您的应用程序要求的客户浏览器功能的工具。具备了基本功能后,可以考虑工具的生产率。一般来说,包含的分析工具越多,可以记录的性能数据类型越多,您可以达到的生产率就越高——您愿意付的钱也就越多。顶级的负载测试程序可以模拟多个浏览器,与大多数应用服务器集成,收集多个服务器主机的性能数据(包括操作系统、JVM 和数据库统计数字),生成可以在以后用高级的分析工具分析的数据集。另一方面,低端负载测试程序是免费的。在那些预算有限的日子里,“免费”的意义是不言自明的。
图 1 展示了免费的负载测试程序 Apache JMeter,它显示了一个自动记录的脚本。
图 1. JMeter 显示一个自动记录的脚本
丰富的功能
我们已经看过了压力测试工具的基本功能,还适合增加什么附加功能呢?不同的负载测试工具的区别在什么地方呢?当然,您最主要的要求是这个工具必须可以模拟您的应用程序客户机。如果您的应用程序使用一些不常见的浏览器功能组合或者其他非标准客户机技术,那么就排除了相当一部分候选者。除此之外,还有其他功能使负载测试的生产率更高。对于决定适合于自己项目的负载测试工具,下面的列表是一个有用的出发点:
模拟您的客户机
首要要求一定是负载测试程序能够处理您的应用程序所使用的功能和协议。
运行多个模拟的客户机
这是负载测试程序最基本的功能,它有助于确定哪些是负载测试程序以及哪些不是(一些框架试图伪装成负载测试程序)。
脚本化执行并能编辑脚本
如果不能编写客户机与服务器之间交互的脚本,那么就不能处理除最简单的客户机之外的任务东西。编辑脚本的能力是最基本的——小的改变不应该要求您重新生成脚本。
支持会话
负载测试程序如果不支持会话或者 cookies,那么就不算是真正的负载测试程序,并且不能对大多数 J2EE 应用程序进行负载测试。
可配置的用户数量
测试程序应该可以让您指定每个脚本由多少个模拟用户运行,包括让您随时间改变模拟用户的数量,因为许多负载测试应该从小的用户数量开始,并慢慢增加到更多的用户数量。
报告成功、错误和失败
每一个脚本都必须定义一个方法来识别成功的交互以及失败和错误模式(错误完全不会有页面返回,而失败可能在页面上得到错误的数据)。
页面显示
如果负载测试程序可以让您检查一些发送给模拟用户的页面,这会很有用,这样您就可以确保测试工作是正确进行的。
导出结果
您常常希望可以用不同的工具来分析测试结果,这些工具包括电子表格和可以处理数据的自定义脚本。虽然许多负载测试工具包括大量的分析功能,但是导出数据的能力使您在以任意的方式分析和编目数据方面具有更大的灵活性。
考虑时间
真实世界的用户不会在收到一页后立即请求另一页——一般在查看一页和下一页之间会有延迟。 考虑时间 这个标准术语表示在脚本中加入延迟以更真实地模拟用户行为。大多数负载测试程序支持根据统计分布随机生成考虑时间。
客户机从列表中选择数据
用户一般不会使用同样的一组数据,每位用户通常与服务器进行不同的交互。模拟用户应该也这样做,如果在交互的关键点,脚本可以从一组数据中选择数据,则可以更容易地让您的模拟用户表现出使用不同数据的行为。
从手工执行的会话记录脚本
相对于编写脚本,用浏览器手工运行会话并记录这个会话然后再编辑会容易得多。
JavaScript
一些应用程序大量使用 JavaScript 并且需要模拟客户机支持它。不过,使用客户端 JavaScript 可能会增加对测试系统上系统资源的需求。
分析工具
测量性能只是成功的一半。另一半是分析性能数据。谁能比编写测试工具的人能更好地开发这种分析工具呢?是的,至少理论是这样。无论如何,您的工具箱提供的分析工具越多,您就能做得越好。
测量服务器端统计数字
基本负载测试程序测量客户机/服务器交互中基于客户机的响应时间。如果同时收集其他统计数字,如 CPU 使用情况和页面错误率就更好了。您得到的统计数字越多,您用负载测试系统可以做的就越多。如果有这种数据,那么就可以做一些有用的工作,如查看服务器负载上下文中的客户机响应时间和吞吐量统计。
结束语
用任何一种工具可以完成的工作常常受到人的技能、知识和想像力的局限。在描述用负载测试工具查看什么内容的时候,我们也展示了使用这种工具的各种可能性。现在,您可以运用您的想像力去开拓更多的可能性。