半岛权威十大直营(官方)网站

Loadrunner案例:某通信企业Web业务系统的性能测试

原创|行业资讯|编辑:龚雪|2016-06-07 11:57:26.000|阅读 1950 次

概述:本文主要为大家讲述一则Loadrunner案例,关于某省电信公司的业务系统的性能测试。

# 界面/图表报表/文档/IDE等千款热门软控件火热销售中 >>

相关链接:

项目背景

该案例是某通信企业Web业务系统的性能测试。该Web业务系统用于管理企业的备品和备件,包括对网络设备的库存管理、库存流转、备品备件的查询统计等功能。其中库存管理、备品备件查询等功能主要是对数据库的增、删、改、查操作,库存流转则主要体现为工作流的实现。

该系统的主要用户是通信企业的备品备件管理人员,通过该系统,管理人员能够对现有的备品备件库数据进行查询、更新,也可以通过该系统提供的业务流程完成备品备件的出库和入库操作。

对系统的测试在系统上线时进行,主要目的是验证系统的性能能否达到用户要求。

性能测试工具Loadrunner

点击下载

项目特点

该项目基于J2EE实现,采用Tomcat作为应用服务器,架构上使用Struts+EJB+Herbinate,在业务上实现了多个流转的流程。

该系统是一个典型的J2EE应用,从性能测试的角度来说,具有很强的代表性。从技术的角度来说,该系统使用了验证码方式防止对系统口令的暴力破解和可能的内部SPAM,由于现在越来越多的系统都采用验证码方式提高系统的安全性,因此在对本案例的描述中也特别给出了针对这种验证码的性能测试解决方案。

该系统的网络环境和设备相对简单,网络环境是企业内部的千兆网络,基本不可能对系统性能造成影响;设备方面,采用一台UNIX服务器作为数据库服务器,一台UNIX服务器作为应用服务器。

该系统是一个以人机交互为主的系统,因此,对系统性能的体现主要通过响应时间来给出。

由于Web应用采用的协议单一(HTTP和HTTPS协议),因此特别适合用商业的性能测试工具(如LoadRunner)来辅助进行测试,本案例的描述中重点结合LoadRunner的使用,描述了在项目性能测试中用LoadRunner等工具进行测试的方法。

性能测试过程

本节描述性能测试的全过程,根据本书第5章的性能测试过程描述,按照PTGM模型分别对性能测试的各阶段进行阐述。

测试前期准备

在了解该项目的基本状况之后,首先开始测试前期准备工作。

1.系统基础功能验证

本案例中描述的性能测试安排在功能验收测试之后,因此在性能测试中不需要额外安排基础功能验证。

2.组建测试团队

根据该项目的具体情况,建立一个5人的团队负责本次测试工作。由于该系统的设备环境和网络环境相对简单,因此没有特别在团队中包括系统工程师,团队的5个成员中,1名是数据库工程师,1名是性能测试设计和分析人员,3名是性能测试开发和实施人员。

在测试开始之前,根据对项目的了解,预计该系统的性能测试难点主要在测试设计和测试脚本实现阶段,由于系统协议单一,架构相对比较简单,且有合适的商业工具可以直接使用,因此在测试工具方面不需要投入太多的精力。

3.测试工具需求确认

考虑到系统测试的要求,确定的测试工具需求如下:

  • 支持HTTP/HTTPS协议层上的测试。
  • 能监控UNIX服务器的主要性能计数器值,如服务器的内存使用状况、CPU使用状况、磁盘I/O情况等。
  • 能监控Windows服务器的主要性能计数器,如服务器的内存使用状况、CPU使用状况、磁盘I/O情况、进程的内存使用情况等。
  • 支持对Oracle数据库的主要性能计数器值进行监控。
  • 支持对Tomcat应用服务器的JVM内存使用状况进行监控。

4.测试工具需求确认

性能预备测试用于对系统建立直观的认识,在正式开始测试之前体验性地使用了本系统的主要功能,根据体验,系统的所有操作均能在4秒之内完成,响应时间相对较长的是登录过程。

测试工具引入

根据测试前期准备确定的测试工具需求,目前市面上的性能测试工具基本都能够支持这些需求,唯一有困难的是“监控Tomcat应用服务器的JVM使用状况”,基本上所有的商业工具都不支持该需求。

最终确定的测试工具包括两个方面的内容:采用LoadRunner工具作为主要的性能测试工具;对Tomcat的JVM使用状况的监控通过自行开发工具来实现。

测试计划

测试计划阶段需要分析用户活动,确定系统的性能目标。

1.性能测试领域分析

根据对项目背景的了解,本性能测试要解决的主要问题为:验证系统是否达到了预期的性能指标。

这些内容对应于第2章中给出的能力验证应用领域。进一步根据第2章的内容,本测试可用的性能测试方法包括PerformanceTesting和StressTesting方法。

2.用户活动剖析与业务建模

本案例描述系统的建模主要通过用户活动建模和业务建模来体现和进行。

根据对被测系统的使用用户进行书面的问卷调查,在问卷基础上进行分析,可以得到如表1所示的典型用户活动分析列表。

表1

注:①“实际使用用户数量”是针对一个具体的业务模块的,此处给出的数据是对某个具体业务模块的估算。本案例中,通信企业实际使用该系统的人数约为1000人,但考虑到选取的“1天”的考察时间范围,每个模块每天的使用者为20~200人不等。

 ②“业务发生数”是根据书面的用户调查方式获取的,具体方法是将用户的平均业务发生数乘以用户数。

表1初步描述了用户对各业务系统的使用情况,可以以此为基础来进一步分析用户场景,并据此设计相应的测试方案和用例,业务场景的分析与企业的实际业务模式相关。

在对用户活动进行建模的过程中,还得到了以下数据:

  1. 平均每天使用该系统的总用户数约为600。
  2. 平均每个用户的loginsession时间为4小时(也就是说,平均每个用户在8小时时间内有4小时处于“使用系统”的状态)。
  3. 平均每个用户在loginsession的时间范围内进行500个业务操作。

根据以上数据,可以用第1章给出的公式进行计算:

并发用户数:600×4/8=300

吞吐量:300×500/(4×60×60)=10,单位是页面浏览数/秒(PageView/sec)。

有了这些数据就可以进行测试场景的设计了。

在分析了用户的行为之后,为了给测试脚本开发提供依据,还需要对每个业务的操作过程进行描述。在本案例中,以“库存流转―审批”为例,对业务操作进行描述。

“库存流转——审批”业务步骤描述如下:

  1. 用户单击“审批”链接,进入审批页面,页面显示所有等待审批的申请单。
  2. 用户选中所有显示审批单中的第一张审批单,单击“审批通过”按钮。
  3. 系统在页面上反馈“审批通过”信息。

从表1中可以看到,该系统的主要业务集中在库存流转流程相关的活动上,因为这些活动都围绕流转进行,在业务场景设计时必须考虑流程之间的交互性。

另外,“导入备件Excel文件”业务的发生频率和实际使用的用户数量都不大,但由于每次的导入操作均会导入大量的数据,导入过程中系统承受的压力很大,因此在设计场景时有必要单独考虑该场景。

3.确定性能目标

本性能测试的应用领域已被确定为能力验证,在确定性能目标时,主要围绕这个方面确定。

本项目是一个开发项目,从需求和设计中可以获得关于该系统性能目标的描述。根据需求和设计文档,该系统的性能约束在文档中的表达如下:

  1. 系统的页面响应时间不超过10秒。
  2. 需要评估导入备件Excel文件对系统性能的影响,如果该操作影响其他业务,需给出建议。
  3. 系统能够稳定运行。

在这些描述中,第(1)条是比较清晰的性能需求描述;第(2)条实际描述的并不是需求,而是希望在性能测试中安排对“导入”操作的性能表现的测试;第(3)条描述的是用户的性能要求,但不够明确。

经过多次沟通,最终确定的明确的性能需求如下:

系统在典型数据量情况下,页面响应时间不超过10秒:典型数据量定义为当前系统的所有备件规模的静态数据和半年的流转数据。

  1. 系统在典型数据量情况下,页面响应时间不超过10秒:典型数据量定义为当前系统的所有备件规模的静态数据和半年的流转数据。
  2. 系统能够在高于实际系统运行压力1倍的压力情况下,持续稳定工作72小时:持续稳定工作定义为在系统运行期间,系统的可用资源不会出现持续性地减少,用户响应速度没有显著变化。

除了这两个直接从文档中反映的系统性能需求,根据和用户、项目经理等的沟通,另外确定的其他性能目标包括:

  1. 评估典型规模的Excel备件文件导入时对系统性能的影响:评估内容包括两个方面,一个方面是对典型规模的Excel文件(考虑到系统实际的备件数据规模,选择一个20MB、包含50000条数据记录的Excel文件)进行导入时的效率评估;另一方面是通过组合场景,判断导入操作对其他操作的影响。
  2. 在页面响应时间要求10秒的情况下,找到系统能够承受的最大用户数量:该要求可以给用户提供一个可扩展性的参考。

表2给出了分析整理后的性能需求描述。

表2

对能力验证应用领域来说,本测试需要重点关注的是业务的响应时间、各服务器的资源使用状况,结合性能测试需求,性能目标可以定义如下:

  1. 在典型用户数量要求的情况下,服务器CPU平均使用率不高于75%,内存使用率不高于75%。
  2. 在稳定性测试的压力情况下,服务器CPU平均使用率不高于95%,内存使用率不高于90%。

4.制定测试时间计划

本案例采用商业性能测试工具LoadRunner进行测试,由于本案例涉及较多的流程交互等内容,因此重点集中在如何设计和实现合理的性能测试脚本,这需要消耗较多的时间和人力资源。

另外,测试结果的分析也需要安排足够的时间进行。本案例的测试时间计划安排如表3所示。

表3

测试设计与开发

测试设计与开发包括测试环境设计、测试场景设计、测试用例设计和测试辅助工具开发多个活动。对本案例而言,测试场景关注用户以何种方式使用本系统,以场景来体现性能测试的目的和目标。

1.测试环境设计

本性能测试需要验证系统在实际生产部署环境上的性能,因此,选择尽可能接近实际生产环境的环境来进行测试。由于本测试的环境就是实际的生产环境,因此在环境设计上,没有太多需要考虑的内容。

最终确定的测试环境如表4所示。

表2给出了用作测试的基础数据量。基础数据量的计算方法在前两个案例中都有描述,在此不再重复。

表4

2.测试场景设计

结合表1的和表2可以很容易地为该案例给出需要的测试场景。

根据上面给出的数据,设定的总并发用户数为300,按照业务模块访问用户数比例给定VU分配比例,为了达到10PageView/sec的吞吐量,每个VU的操作之间间隔应该为300/10=30秒。

根据调查的结果,我们确定了几个典型的测试场景,如表5所示。

表5-1

表5-2

3.测试用例设计

确定测试场景之后,原有的业务操作描述可以更进一步完善为可映射为脚本的测试用例描述。

在本案例中,可以将用户业务操作形成更详细的用例步骤。例如,“审批”业务可以描述如下:

用例编号:TC_XXXX_XX-1

用例条件:用户已登录,登录用于具有审批的权限

用户步骤和验证方法:

  1. 用户单击“库存流转”链接,进入库存流转页面。
    【验证】页面出现“库存流转”提示字符串。
  2. 用户在页面左侧树视图上单击“审批”链接,进入审批页面。
    【验证】页面上出现“申请单列表”提示字符串。
  3. 用户在页面给出的等待审批的申请单列表中选择最上方的一个,单击“审批”按钮,进入审批页面。
    【验证】给出选中审批单信息,页面上出现被选中审批单的编号。
  4. 用户输入审批信息,单击“通过”按钮。
    【验证】页面上出现“审批通过”提示字符串

从该用例的描述可以看到,在每个操作步骤之后,都给出了相应的验证手段。对性能测试来说,验证手段同样关键。性能测试工具(如LoadRunner等)在性能测试过程中为了VU的效率,一般只通过HTTP返回的HTTPCode判断请求是否成功,对于典型的如HTTP500、HTTP404等错误,LoadRunner能够判断,但如果采用了自定义错误页面,或是返回了表示异常状态的页面,LoadRunner便不能发现。

基于以上原因,通常需要在脚本中添加一些用于验证返回页面是否正确的代码,最常用的方法是判断页面中是否存在特定的字符串。因此,在每个用例中都描述了每个步骤结果的验证方法。

4.脚本和辅助工具的开发

本案例采用LoadRunner作为性能测试工具,下面通过该案例首先介绍LoadRunner在性能测试中的一般应用步骤,然后重点说明在性能测试过程中遇到的问题和解决方法,依次演示LoadRunner使用中的一些技巧和技术。

(1)LoadRunner的性能测试过程。

用LoadRunner工具辅助进行性能测试,一般包括录制和调试脚本、设置场景、运行场景、收集结果并分析4个活动。

录制和调试脚本活动使用LoadRunner的VirtualUserGenerator应用(下文中简称为VUGenerator)完成,运行该应用,选择合适的录制协议,打开被测应用的客户端程序(对B/S应用,客户端程序就是浏览器),按照预期即可进行录制。LoadRunner录制的脚本中体现的是客户端和服务器之间的通信数据以及相互的交互关系。

脚本的录制依据事先分析出的用户活动和案例。按照测试用例设计中给出的具体操作描述,打开VUGenerator工具,输入应用的起始URL,根据用例描述执行操作,录制脚本。LoadRunner针对Web应用录制的脚本默认分为vuser_init、Action和vuser_end3段,其中,vuser_init和vuser_end段只在脚本运行时执行一次,而Action段的执行次数由脚本或场景的RuntimeSetting控制。一般来说,在录制脚本时,会把Login和Logout的步骤分别放在vuser_init和vuserend段中,而把针对业务的操作步骤放在Action段中。

VUGenerator同时提供了对脚本调试的良好支持。脚本录制完成后,需要经过一个仔细的调试阶段才能保证脚本确实准确无误地反映了计划中的测试意图。调试过程中经常进行的操作是参数化、关联和调试输出。

设置场景活动由LoadRunner的Controller工具支持。运行Controller工具,根据测试设计中确定的典型测试场景(见表1),将不同的脚本按照场景中设计的比例分配到一个场景中。并且,测试场景中还需要根据设计的典型场景中的“性能计数器”项目,设置需要进行监控的性能计数器内容。图1描述的是根据表5设计的“系统应用典型场景1”实施的场景。

图1

场景设置涉及的细节内容较多,除了在该场景中分配执行各脚本的VU数量外,还需要根据测试设计添加需要增加的性能计数器(见图2),最后,特别需要关注的是针对脚本的RuntimeSetting设置(见图3),例如,表5给出的“典型场景1”中描述了需要每个脚本Action部分迭代100次,这就需要在Controller的设置中给出每个脚本的迭代次数设置。

图2

图3

运行场景活动相对简单,单击Run页面中的StartScenario按钮,Controller就会自动开始运行场景,并在ScenarioStatus中显示运行时的信息。

收集结果并分析活动需要Analysis应用的支持,Analysis应用可以被独立启动,也可以从Controller程序中调用。从Controller程序中调用时,Analysis应用直接读取本Controller当前场景运行时的信息。图4给出了Analysis应用运行时的界面。

图4

Analysis应用能够根据用户设定的性能计数器生成各种性能报表。不过,Analysis最多也只能起到辅助进行性能测试分析的作用,要对性能测试的结果进行分析,还要依靠测试分析者的经验、技能和对系统的了解。

(2)录制“登录”脚本。

针对该应用录制登录脚本时,验证码是一个首要的困难。

验证码是在进行登录或内容提交时,页面上随机出现的人工可识别但机器不可识别的验证字符串(一般是采用背景、扭曲等方式产生的图片),要求登录或提交内容的同时输入,如果验证码输入错误,则不允许进行要求的操作。

本案例中的被测系统使用了验证码技术,其要求输入验证码的页面内容如图5所示。

验证码可以有效防止采用机器猜测方法对口令的刺探,目前己经被许多Internet或Intranet应用接受为标准的实现方式。但对性能测试来说,验证码却带来了很大的问题。因为验证码具有阻止通过自动工具尝试的特性,因此,对于本质上也是自动化工具的性能测试工具,验证码同样具有相当的威力。

图5

具体到本案例系统,在录制脚本时,LoadRunner可以录制用户输入的“用户名”、“密码”和“验证码”信息,但在回放时,由于要求的验证码与录制时的验证码不可能相同,因此回放必然会失败。

为使性能测试能够顺利进行,需要采用某种方法解决上述问题。在笔者的实际工作中,通常使用下面3种方法解决该问题。

第1种方法是最容易想到的方法——在被测系统中暂时屏蔽验证功能,也就是说,为性能测试临时修改应用,在应用中屏蔽验证码(也就是说,无论用户输入的是什么验证码,应用都认为其是正确的)。

这种方法最容易实现,对性能测试结果也不会有太大的影响。这种方式去掉了“验证验证码正确性”这个环节,从理论上来说,测试得到的结果与存在“验证验证码正确性”环节的应用系统存在细微的差异,不过考虑到此环节一般不会成为系统性能瓶颈,因此认为这种处理方式对性能测试结果没有太大的影响。

这种方法对于处于未上线状态或在受控的测试环境中运行的系统非常适用,但对于已经实际上线运行的系统来说,这种方法有一个明显的问题:屏蔽验证功能会对己经在线运行的业务造成非常大的安全性风险。

因此,我们建议在受控的测试环境中采用该方法,但对于已上线的系统来说,不推荐使用该方法。

第2种方法是在第1种方法的基础上稍微进行一些改进。

第1种方法的主要问题是安全性问题,为了应对对在线系统安全性的威胁但在其中留一个“后门”——设定一个“万,可以在修改程序时不取消验证,能验证码”,只要用户输入该“万能验证码”,应用就认为验证通过,否则,还是按照原先的验证方式进行验证。

这种方式仍然存在安全性问题,但由于可以通过管理手段将“万能验证码”控制在一个较小的范围内,而且只在性能测试期间保留这个“后门,基本上可以看作是可靠的。

相对第1种方法来说,这种方法在安全性方面进行了改进,在能够通过管理手段控制“万能验证码”范围的情况下,该方法不失为一种简单易行且相对安全的方法。

第3种方法采用更进一步的方法来处理验证码的问题。

LoadRunner能够调用外部的DLL或组件接口,考虑到这个特性可以根据“验证码验证”的实现,写一个获取验证码的动态库,在测试脚本中调用其接口即可。关于如何在LoadRunner中使用外部DLL,参见本书第11章的内容。

在使用以上验证码处理的方法时,特别要注意,如果针对的是己上线运行的实际系统,无论用哪种方法,测试完成后,都必须立刻将应用恢复,并对系统进行一次安全审计,以免在测试期间被他人入侵。

在本案例中,采用第2种方法来解决验证码带来的问题。

以下是脚本中与登录相关的部分代码:

图6-1

图6-2

这段脚本中灰色背景的粗斜体内容就是修改系统实现后留下的“后门”,其中,5847是在代码中控制的一个“万能验证码”,主要用户输入该验证码,系统就认为验证通过。

细心的读者还会发现,这段代码已经经过了关联处理,其中粗斜体标识的内容就是关联产生的参数内容。这段代码的关联是通过LoadRunner的“自动关联”方式实现的,具体实现方法请见第11章。

解决了验证码和登录时关联的问题后,登录脚本还需要处理的另一个问题就是针对输入的用户名和口令进行参数化处理,本案例中共使用了10组不同的用户名和口令组合。对用户名和口令实现参数化的具体步骤请见第11章。

(3)录制“新建申请单”脚本。

录制“新建申请单”脚本需要首先按照设计中该用例的操作步骤进行录制,以下是按照“新建申请单”用例步骤进行录制后生成的部分脚本代码。

图7

从脚本中可以看到,脚本中给出了申请的发起时间和到期时间,为了使脚本具有更好的适应性,我们决定将这两个时间分别以“当前时间”和“当前时间的前4天”进行替代,这需要对脚本进行参数化操作。在VUGenerator中,选中需要参数化的内容(两个时间),从右键菜单中选择Replacewithaparameter命令,在出现的对话框中设定参数类型为Date/Time,设置时间格式为适合的格式,如图8所示。

设置到期时间时,需要将参数在当前时间的基础上再增加4天。图9所示为设置到期时间的对话框,要注意其中设置的Offsetparameterby选项。

另外,为了便于直观地识别数据是在哪次操作时插入的,在新建申请单时将“备注”的内容修改为“test-”+“当前时间”(当前时间精确到秒)。

图8

图9

参数化修改完成后的脚本代码如下:

图10

除了参数化之外,在脚本中还需要体现“验证返回结果是否正确”,验证返回结果是否正确通过LoadRunner提供的web_eg_find函数实现。该函数的原型是:

图11

在脚本中加入该函数可以根据页面是否存在指定的文本等来验证系统处理的正确性。在用例设计时我们给出了“审批”业务的用例,其中包括的每个“验证”点都可以用这种方式来处理。例如,对给出的“【验证】页面上出现‘申请单:列表’提示字符串”要求,可以在指定的发送请求的语句后添加下面的语句来验证:

Web_reg_find("Text=申请表:列表",LAST);

该语句可以验证返回的页面上是否包含“申请表:列表”文本内容。

(4)录制“审批”脚本。

“审批”涉及到“流程”的概念,测试场景中要求一部分用户“新建”申请单,另一部分用户对已有的申请单进行“审批”操作。录制脚本时,假设录制了对某一条己有的申请单的“审批”,在回放时,如果指定的申请单已经被处理,则脚本的处理就会出错。

图12给出了审批时能看到的待审批申请单列表,在性能测试过程中,每个VU看到的列表都会有所不同,为了使性能测试时每个VU都能够顺利执行(处理待审批的申请单),必须在脚本中约定申请单的处理规则。为简单起见,我们约定的规则是“每个VU都只处理当前未被处理申请单列表中的第一条记录”。

图12

为了实现这个规则,必须对录制后的脚本进行一些处理。未处理的录制生成脚本的相关部分代码如下:

图13

/*动作2——单击指定的审批单记录,给出审批单的详细信息,允许用户对其进行审批*/

图14

/*动作3——填写审批单后进行提交,提交为"通过审批"*/

图15

以上代码中的数字“20051223004”表明了要处理的记录的ID。动作2和动作3都使用了唯一标识审批单记录的ID(数字20051223004)来对指定的审批单操作,那么,这个审批单的ID是从哪里得到的呢?

注意动作1,该动作返回当前所有可被处理的审批单列表,几乎可以肯定,用于标识审批单ID的数字是作为该动作的响应返回给我们的。在VUGenerator中切换到TreeView视图(单击工具栏中的ViewTree按钮),选择ServerResponse选项卡,可以看到图16所示的结果。

将图16显示的信息与图15进行对比,图15是浏览器呈现的页面,而图16给出的则是该页面的对象信息和以文本方式显示的HTML内容。

图16左侧树型的3个radio:appids节点对应于图15显示的3条待处理审批单。而且,从右侧显示的HTML文本内容来看,这个Radio的value就是在后续脚本中需要使用到的用作ID的数值。

图16

根据约定的规则,只要求每个VU处理第一条未审批的记录,这样问题就转变成了一个典型的关联问题―如何从动作1返回的HTML文本中获取到第一条未审批记录的value值。

本书的第11章详细描述了相关的内容,对Web应用的性能测试脚本而言,主要的关联函数是web_reg_save_param函数。该函数必须放在产生需要获取关联内容的语句之前(在本案例中,要放置在“动作1”的语句之前),其原型是:

图17

其中,第一个参数是关联操作获取的内容保存的变量;最后一个参数是LAST;中间的参数描述了约束要获取关联内容的各种属性。指定关联属性时,必须指定“左边界”和“右边界”,视情况还可指定其他属性。对本案例来说,需要进行关联的内容在返回的HTML文本中,文本内容为:

图18

需要通过关联操作获取的内容是“20051223004",可以选取左边界为“value="”,右边界为“"”。考虑到返回的HTML文本中能够与选取的左边界与右边界匹配的内容较多,因此还需要通过ORD属性指明具体的需要关联的内容位置。

最终关联处理完成后的脚本代码片断如下:

图19

添加的web_reg_save_param语句表明,需要关联的内容存在于下一个Request为“"”返回的HTML内容的BODY中,该内容左边界为“value="”,右边界,在这个HTML内容的BODY中,我们想要通过关联获取的内容顺序排在第4个出现符合约束条件的位置。

(5)录制其他脚本

录制其他脚本的过程相对比较简单,主要的技术细节和难点都在上几个脚本的录制过程中进行了详细描述,在此不再赘述。

测试执行与管理

在测试执行与管理之前的过程和活动中,己经明确规划了本性能测试的环境、场景和脚本,在本过程中,只需要按照前面阶段的要求,将测试场景和脚本进行部署,然后执行测试并记录结果即可。

建立测试环境

建立测试环境只需要按照测试设计中设计的环境设计内容部署测试环境。部署测试环境的工作一般由团队中的系统工程师完成,可以采用CheckList帮助进行测试环境的部署。

表6给出了一个CheckList的示例。

表6

部署测试脚本和测试场景

根据设定的性能测试场景,在LoadRunner工具中对其进行部署,部署过程请参考本书的第11章。

多学两招:

本案例共设定了5个场景和多个业务用例(脚本)。在场景和用例较多时,如果对其管理不善,常常会导致测试过程中的麻烦。因此,在实际测试过程中,一般使用具有一定意义的场景和脚本名称标识不同的场景和脚本。

例如,在本案例的测试过程中,使用“测试项目名称_场景名称”的方式为LoadRunner中的场景文件命名;使用“测试项目名称_业务名称_特殊说明”为LoadRunner中的脚本命名。这样在后续的测试过程中,可以很容易地根据场景和脚本的名称识别出场景和脚本的用途。

执行测试和记录结果

本性能测试中使用LoadRunner作为性能测试工具,性能指标的数据主要通过LoadRunner的Monitor等获得,因此主要通过LoadRunner来记录数据。唯一例外的是针对Tomcat的服务器状态监控,这部分通过Tomcat提供的StatusSeverlet进行监控,监控得到的数据保存在本地文件中,通过Excel进行处理并以图表的方式呈现。

用LoadRunner执行测试非常简单,只需要通过Controller的GUI界面就可以完成执行和监控工作。这部分的具体内容请参考本书的第11章。对Tomca秒获取一次数据t使用的JVM进行监控通过Tomcat的statusservelet实现,每5,获取的数据保存在文本文件中。

但在实际的性能测试过程中,由于一些设置等问题,有时候会遇到执行出错的情况。典型的情况是脚本在单独回放时没有任何问题,但部署到场景中执行时却出现一些奇怪的错误。

本案例的执行过程中就出现了这样的情况。设定好测试场景并开始执行后,从Controller的界面上可以看到“HTTP404:CannotfindpageXXXX”的错误信息。刚看到这个问题时觉得特别奇怪,因为在回放的过程中没有出现过这样的错误,而且,从计数上看,通过的Transaction一共只有500个,除去200个vuser_init和vuser_end的Transaction,通过的只有300个,也就是说,每个脚本都只有第一次迭代的执行是正确的。

仔细检查WebServer的日志,发现该日志中有多个访问timeout.jsp的记录,询问开发人员得知,session超时后才会访问这个页面。首先排除了由于迭代之间的等待时间过长导致超时的可能,随后经过仔细分析,觉得问题产生的原因可能与LoadRunner的设置有关。

HTTP协议本身是非面向连接的无状态的协议,为了适应Web应用需要的交互特性,一般需要使用sessionid来标识一些会话中的各个request和response为了保留住sessionid,一般的做法是用hiddenfield、cookie或是在URL上附加sessionid来解决,我们怀疑本题的出现与sessionid的处理相关。

查看LR记录的页面访问数据(见图20),可以看到,在ClientRequest中附带了JSESSIONID的信息,可见,该应用是用cookie解决sessionid的问题的。

图20

接下来,可以大胆猜测,出现问题的原因可能是在两次迭代之间LR清除了cookie,这就使在第一次迭代时应用操作成功,但在随后的执行中由于不存在sessionid的标识,使后续的操作全部失败。

检查脚本RuntimeSetting的设置(见图21),果然Simulateanewuseroneachiteration选项被选中。LoadRunner的Manual里对Simulateanewuseroneachiteration选项的解释是:“选中该选项后,LoadRunner在每次迭代时清除当前的上下文。”iteration选项的解释是:“选中该选项后,LoadRunner在每次迭代时清除当前的上下文。”

图21

取消选中该选项,重新运行Controller中的场景,结果正常。

多学两招:

上面描述的问题是由sessionid引起的,更准确地说,是因为应用要支持session而导致应用使用了一些特殊的处理方法引起的。那么,究竟什么是session,session一般在程序中以何种方式存在呢?

首先说一下session的起源。

HTTP协议本身是无状态的,这与HTTP协议本来的目的是相符的,客户端只需要简单地向服务器请求下载某些文件,无论是客户端还是服务器都记录彼此过去的行为,每一次请求之间都是独立的。

然而,对目前的大部分Web应用来说,“无状态”导致许多应用都不得不花费大量的精力记录用户的操作步骤,人们很快发现,如果能够提供一些按需生成的动态信息,会使Web变得更加有用,这种需求一方面迫使HTML逐步添加了表单、脚本、DOM等客户端行为,另一方面在服务器端则出现了CGI规范以响应客户端的动态请求,作为传输载体的HTTP协议也添加了文件上载、cookie这些特性。其中cookie的作用就是为了解决HTTP协议无状态的缺陷所作出的努力。至于后来出现的session机制则是又一种在客户端与服务器之间保持状态的解决方案。下面用几个例子来描述一下cookie和session机制之间的区别与联系。假设在一个快餐厅有累计消费满200元返50元的优惠,为了能够准确地返给用户正确的金额,可以有这样几种方案:

(1)该店的店员很厉害,能记住每位顾客的累计消费金额,只要顾客一走进快餐厅,店员就知道该怎么对待了。这种做法就是协议本身支持状态。

(2)发给顾客一张卡片,上面记录着消费的数量,一般还有一个有效期限。每次消费时,如果顾客出示这张卡片,则此次消费就会与以前或以后的消费联系起来。这种做法就是在客户端保持状态。

(3)发给顾客一张会员卡,除了卡号之外什么信息也不记录,每次消费时,如果顾客出示该卡片,店员则在店里的记录本上找到该卡号对应的记录并添加一些消费信息。这种做法就是在服务器端保持状态。

由于HTTP协议是无状态的,而出于种种考虑也不希望其成为有状态的,因此,后面两种方案就成为现实的选择。具体来说,cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案。同时也看到,由于采用服务器端保持状态的方案在客户端也需要保存一个标识,所以session机制可能需要借助于cookie机制来达到保存标识的目的。

session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。

当程序需要为某个客户端的请求创建一个session时,服务器首先检查这个客户端的请求里是否已包含了一个session标识——sessionid,如果包含,则说明以前已经为此客户端创建过session,服务器就按照sessionid把这个session检索出来使用(如果检索不到,可能会新建一个);如果不包含,则为此客户端创建一个session并且生成一个与此session相关联的sessionid,sessionid的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,该sessionid将在本次响应中返回给客户端保存。

保存sessionid的方式可以采用cookie,这样在交互过程中,浏览器可以自动按照规则把这个标识发送给服务器。一般将cookie,设定为类似于SESSIONID的名称,如weblogic对于Web应用程序生成的cookie,JSESSIONID=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764,该cookie的名字就是JSESSIONID。

测试分析

测试执行完成后,通过LoadRunner的Analysis模块,可以对测试过程中得到的性能数据进行分析。

针对场景1、场景2、场景3的基础性能分析

在进行性能分析时,首先可以检查Analysis模块提供的SummaryReport。下面以系统应用典型场景1为例进行分析。

图22给出了该场景运行后的SummaryReport。

图22

从图22可以看出,整个测试过程中我们所关心的各业务(备件信息、查询、申请表和登录)的响应时间均超过了性能需求中定义的10秒,因此从总体来说,本系统没有达到性能要求。

到此为止,已经得出了总体的结论,但是,性能测试结果的分析过程还远远没有结束。因为我们的目的并不仅仅要得出“系统是否满足预期的性能要求”这样一个结论,还应该给出更加具有建设性的意见和建议。

例如,还需要考虑:性能是在什么时候开始变坏的?性能可能的瓶颈在哪里?

为此,我们首先关注性能测试过程中业务的执行成功比例。图23给出了所有事务执行情况的柱状图。

图23

从图23可以看到,所有的事务执行都为成功,也就是说,测试结果基本可信。另外,从SummaryReport中的HTTP返回码统计图(见图24)中可以看到,大部分的HTTP返回码都是200和302,这说明应用在HTTP返回层面上是成功的,少部分的404返回码通过对日志的检查,可以确认是由于部分图片文件缺失引起的,而这部分图片文件的缺失是在开发过程中造成的,并不影响应用本身的正确性,也不影响应用性能测试结果的有效性。

图24

确认测试结果的有效性之后,接下来对应用的性能表现进行初步的分析。

图25给出了“申请单”业务的“RunningVuser-AverageTransactionResponseTime关联曲线,从该关联图可以看出,应用系统的性能随着RunningVusers数量的变化有一个明显的变化趋势。

图25

多学两招:

LoadRunner的Analysis应用默认并不会为每个事务生成RunningVusers-AverageTransactionResponseTime图形,该图形需要用户通过Analysis应用提供的功能自行生成。

具体的操作步骤如下:

  1. 选中RunningVusers页面,在图形上单击鼠标右键,选择MergeGraph命令。
  2. 从弹出的对话框中选择AverageTransactionResponseTime,从Merge类型中选择Correlate,单击OK按钮。
  3. Analysis应用会打开一个新的页面,该页面显示RunningVusers-AverageTransactionResponseTime曲线。

在图25中,排除那些明显的离散点,Vuser的数量从0至150增加时,各事务的性能表现基本保持稳定;当Vuser的数量从150至200增加时,事务的响应时间呈缓慢的线性增长状态;当Vuser的数量超过200时,事务的响应时间急剧增加。

根据本书第1章中描述的性能下降曲线分析法可以知道,150个用户为最佳状态下的最大并发用户数。从图中可以看到,当Vuser增长到180时,基本上所有事务的响应时间都在10秒以内,因此,根据需求和性能下降曲线分析法,可以得出以下结论:

  1. 在系统应用典型场景1条件下,被测系统在180个并发用户访问的情况下事务响应时间小于10秒。
  2. Vuser为200是该系统性能表现的拐点。
  3. “申请单”事务是性能相对最差的事务。

为了确定影响性能的主要因素,我们采用同样的方法得到RunningVusers-UNIXResources关联曲线。图26给出了两台服务器的CPU使用状况和RunningVusers的关联曲线。

图26

从图26可以看到,当Vuser超过110时,应用服务器的CPU使用率就已经超过了预期的75%,而将应用服务器和数据库服务器的CPU使用率进行对比发现,数据库服务器的CPU使用率一直都很低。由此可见,应用服务器的CPU应该是系统性能的瓶颈之一。

同样,两台服务器的内存使用状况和RunningVusers的关联曲线也可用于比较,在本案例中,经过比较发现,在整个性能测试过程中,两台服务器的内存使用都没有超过可用内存的70%,由此可见,可用内存并不是性能瓶颈之一。

对应用服务器来说,在性能测试中,除了关注服务器的内存使用状况外,一个更重要的需要关注的内容是JVM内存的使用状况。

图27给出了应用服务器的JVM内存使用情况。

图27

多学两招:

图27并非LoadRunner的Analysis应用生成的报表,而是将数据文件经过Excel处理后得到的曲线图形。

在本案例中,由于采用的应用服务器是Tomcat5,LoadRunner不能直接支持对该应用服务器JVM内存使用状况的获取,因此我们自行编写了一个小程序,通过Tomcat5提供的Servelet获取JVM使用信息并将其写入本地文件中。测试结束后,将生成的本地文件用Excel进行处理,得到的就是图27所示的曲线图。

从图27可以看到,在整个测试过程中,应用服务器的JVM可用内存处于相对充裕的状况,应该说JVM的可用内存不是性能瓶颈。但需要注意的是,JVM的内存使用呈现出锯齿状的波动,很可能在代码中存在产生了过多的临时对象等情况。

其他的场景可以采用类似的方法进行分析。分析表明,在测试方案中计划的3个不同场景均存在同系统应用典型场景1类似的情况。

针对场景1、场景2、场景3的页面分析

通过以上分析,可以基本解了应用的性能能力以及影响性能的系统瓶颈。在接下来的分析过程中,我们还希望了解到底哪个页面在测试过程中的性能表现最差,表现差的具体原因是什么。

LoadRunner的Analysis应用提供了对页面进行分解(breakdown)分析的辅助功能。下面以“申请单”事务为例,说明对页面进行breakdown分析的方法和过程。

在AverageTransactionResponseTime页面上单击鼠标右键,从弹出的菜单中选择ShowTransactionBreakDownTree命令,此时Analysis应用的左侧会出现一个TransactionBreakdown树型窗口,窗口中显示所有事务的树型列表(见图28)。

图28

在该列表上双击需要关注的事务,则可以打开一个新的WebBreakdown页面(见图29)。

图29

从图29可以看到,左侧的Breakdown列表中列出了每个事务所包含的页面请求动作,而对于每个页面请求动作,用户可以从DownloadTimeBreakdown、ComponentBreakdown(overtime)、DownloadTimeBreakdown(overtime)和TimetoFirstBufferBreakdown(overtime)4个不同的角度来对一个请求的响应进行分析。

从分析的角度来说,首先会关注每个请求响应所花费的时间,从而找出几个最关键的请求(页面),然后对其进行更详细的分析。以本案例来说,考察“申请单”事务,//server:7001/bill/worklist.jsp?rd=0.5476723708419389请求的响应花费了最长的响应时间。图30给出了其响应时间的曲线。

图30

对这个具体的请求,可以首先从ComponentBreakdown(overtime)图表上看返回页面的每个组件所花费的具体时间。具体方法是选中ComponentBreakdown(overtime)单选按钮。

图31给出了进行ComponentBreakdown(overtime)分解后的曲线图形。

图31

结合图30和图31可以很清楚地看到,在性能测试执行到45分钟左右时,返回页面的几个部件的响应时间都非常长,最为典型的是tool_del.gif、done_click_bg.gif等图片文件。而从DownloadTimeBreakdown图形中可以看到(见图32),这些图片都非常小(小于1KB),而且这些图片的平均downloadtime都很短,只在45分钟附近才出现响应时间急剧增长的情况。

图32

从这里基本可以断定,引起这些图片响应时间过长的问题应该在于系统的吞吐量受到了限制,由于我们关注的部件是静态的图片文件,也就是说,该问题主要是由于应用服务器在该时刻处理静态文件时的吞吐量受到限制而引起的。

为了进一步验证我们的结论,在TimetoFirstBufferBreakdown(overtime)的图形中(见图33)可以看到,在45分钟左右,请求tool_del.gif文件的所有的时间消耗都是Servertime。

图33

结合整个测试过程的RunningVusers、HitsperSecond以及Throughput的曲线(见图34),可以看到,在45分钟左右,RunningVusers保持在高水平上,但此时的吞吐量有一个明显的变低的趋势,说明此时应用服务器已经遇到了瓶颈,而且,该瓶颈表现在请求的静态文件的响应时间显著变长。

根据这些分析,基本可以得出以下结论和建议:

  1. 在测试进行到45分钟时,系统遇到了一个明显的性能瓶颈,该瓶颈的表现是响应时间明显变长。
  2. 该性能瓶颈的产生主要是由应用服务器引起的,从应用服务器的表现来看,在该时刻对静态文件的请求响应速度非常慢,而且服务器吞吐量明显受到了制约。
     

    图34

  3. 应用服务器的瓶颈之一是服务器的CPU,但并发用户数应该是一个引起吞吐量制约的因素。
  4. 如果需要进一步确定系统的性能瓶颈,建议采用类似RBI的方法,首先纯粹通过静态文件检查各种不同的并发条件下应用服务器的吞吐量限制,然后与场景的测试结果比较,检查是否是由于应用服务器本身的吞吐量限制,从而决定进一步的调优策略。
  5. 如果最终的问题定位在应用服务器对静态文件的吞吐量上,可以考虑采用Apache+Tomcat的架构,用Apache处理静态页面文件和图形文件,用Tomcat处理JSP文件。

最后要说明的是,根据我们对测试结果的分析,性能的主要瓶颈在于应用服务器,因此在本案例中基本没有对数据库服务器的性能指标进行关注和分析。

针对稳定性测试场景的性能分析

对应用系统的稳定性测试,重点在于通过压力测试,检查长时间运行条件下的应用系统运行状况,以及各服务器的资源使用状况。

测试设计中设计的运行时间是72小时,主要的测试关注点包括:

  1. 服务器内存使用状况。
  2. 应用服务器JVM内存使用状况。
  3. 持续测试过程中的系统性能表现(响应时间)。
  4. 数据库服务器的主要性能指标。

实际测试过程中,由于对场景1~场景3的测试结果表明,系统根本无法支持预期的压力测试的用户访问量,因此没有对其进行稳定性测试。

针对数据导入场景的性能分析

数据导入场景测试除了关注系统的响应时间等性能表现外,还特别关注服务器的磁盘I/O是否达到磁盘处理能力的极限。

系统响应时间性能的分析与上面的分析过程一样,对磁盘I/O的关注通过UNIX系统提供的iostat命令获取相关数据并进行分析。

计算最大磁盘I/O数的公式在本书的第3章中进行了详细的讨论,在此不再赘述。在本案例中,没有发现系统存在服务器磁盘I/O方面的瓶颈。

四、案例小结

该案例展示了一个完整的应用LoadRunner对Web应用进行性能测试的全过程,它遵循PTGM模型进行性能测试,并重点给出应用LoadRunner进行性能测试需要关注的重点内容,展示了使用LoadRunner进行性能测试结果分析的方法。

该案例系统是一个具有典型代表性的基于J2EE的Web应用系统,采用标准的HTTP协议,因此主要使用LoadRunner这个商业工具作为性能测试工具。本案例非常详细地描述了LoadRunner在实际应用中需要注意的一些问题,介绍的一些技巧和技术都值得读者仔细体会。

本案例还额外讨论了性能测试时验证码的处理方法,并根据一次解决实际问题的方法介绍了session这个对Web系统非常重要的概念。在对验证码处理方法的讨论中,给出了3种可能的解决方案,逐一讨论了各种方案的优点和缺点,并给出了每种方案的适用场合和使用注意事项。

使用LoadRunner对性能测试结果进行辅助分析是使用LoadRunner进行性能测试时的重要内容,本案例通过有针对性地重点描述系统测试结果的分析过程(包括基础分析和页面响应分析),并结合性能下降曲线分析方法,演示了对性能测试结果的分析过程。本案例描述的分析过程当然不是唯一的分析方法和过程,但确实是具有代表性的分析方法,希望读者能够仔细体会。

当然,就本案例本身来说,并不是针对被测的Web系统的全部性能测试内容(在对本系统的实际性能测试中,我们还按照RBI的方法对其进行了吞吐量测试、并发测试等),而只是为了说明性能测试进行了有针对性的简化的一个案例描述,因此,读者在学习体会本案例的过程中,也应该更深入的思考——如果你是这个性能测试项目的负责人,还需要关注哪些方面?


标签:性能测试网页测试软件测试技术

本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@wqylolg.cn


为你推荐

  • 推荐视频
  • 推荐活动
  • 推荐产品
  • 推荐文章
  • 慧都慧问
相关产品
Parasoft C/C++test

针对 C/C++ 软件开发提供统一、完全集成的测试解决方案。

LoadRunner

LoadRunner是一款负载测试软件,可使您精确洞察端到端系统性能,以便在应用正式推出之前识别和解决其中的问题。

Unified Functional Testing (UFT)

Unified Functional Testing (UFT),原名QuickTest Professional (QTP),是一款自动化功能测试软件。

HP Performance Center(HP PC)

HP Performance Center 软件是一款企业级性能测试平台。设计用于推动标准化进程、集中式管理、全球协作以及形成卓越的性能测试中心。

title
title
扫码咨询


添加微信 立即咨询

电话咨询

客服热线
023-68661681

TOP