你好,我是茹炳晟。今天我和你分享的主题是:无实例无真相之基于LoadRunner实现企业级服务器端性能测试的实践(下)。
今天,我会继续和你分享如何基于LoadRunner完成企业级服务器端的性能测试。通过我上一次的分享,你已经清楚知道了,整个性能测试过程可以分为五个阶段,并且解决了整个测试过程中最难的一部分工作,即如何获取具体的性能测试需求。
现在,我们先来回顾一下,性能测试包含的五个阶段:性能需求收集以及负载计划制定、录制并增强虚拟用户脚本、创建并定义性能测试场景、执行性能测试场景,以及分析测试报告。所以,今天,我们就要解决剩下的4个阶段的问题了。
我已经在上篇文章中和你提到,完成了性能测试需求分析后,你就已经明确了要开发哪些性能测试脚本。现在,我们就一起来看看开发性能测试脚本的步骤,以及相关的技术细节。
从整体角度来看,用LoadRunner开发虚拟用户脚本主要包括以下四个步骤:
识别被测应用使用的协议;
录制脚本;
完善录制得到的脚本;
验证脚本的正确性。
这里需要注意的是,完善录制得到的脚本这一步,会包含大量的技术细节,也有很多对你来说可能是新概念的名词,所以我会着重讲解这一步,帮你克服性能测试道路上的这些“拦路虎”。
步骤1:识别被测应用使用的协议
如果你已经和系统设计、开发人员沟通过,明确知道了被测系统所采用的协议,那么你可以跳过这一步。如果还不知道具体使用的哪种协议的话,你可以使用Virtual User Generator模块自带的Protocol Advisor识别被测应用使用的协议,具体的操作方法也很简单:
在Virtual User Generator中依次点击File、Protocol、AdvisorAnalyze、Application,展开这些菜单。
在打开的界面上按要求填写被测应用的信息。
Protocol Advisor会自动运行被测系统。如果是网页应用,就会打开浏览器。
在页面上执行一些典型的业务操作,完成这些业务操作后点击"Stop Analyzing"按钮停止录制。
Protocol Advisor会根据刚才录制的内容自动分析被测应用使用的协议,并给出最终的建议。
接下来,你就可以使用Protocol Advisor建议的录制协议开始脚本录制工作了。如图1所示就是Protocol Advisor给出的建议录制协议界面。
步骤2:录制脚本
脚本录制的基本原理是,通过GUI界面对被测系统进行业务操作,Virtual User Generator模块在后台捕获GUI操作所触发的客户端与服务器端的所有交互,并生产基于C语言的虚拟用户脚本文件。
也就是说,录制脚本的过程需要通过GUI实际执行业务操作,所以我建议你在开始录制脚本前,先多次演练需要这些GUI操作步骤,并明确知道哪些操作步骤会对服务器端发起请求。
我们要知道哪些操作步骤会对服务器发起请求的原因是,要将这些操作步骤在虚拟用户脚本中封装成“事务”(Transaction)。封装为“事务”的目的是统计响应时间,因为LoadRunner中的响应时间都是以“事务”为单位的。
具体的录制步骤,主要包括如下三步,
首先,选择Create/Edit Scripts进入Virtual User Generator创建脚本的协议选择界面。
选择正确的协议后进入Start Recording界面,选择需要录制的应用类型,并填写应用的详细信息。如果是Web应用,Application type就应该选择Internet Application,然后选择浏览器并填写这个Web应用的URL,完成后自动打开浏览器。
在该浏览器中执行业务操作,Virtual User Generator模块会记录所有的业务操作,并生成脚本。
在录制脚本的过程中,我强烈建议直接对发起后端调用的操作添加事务定义,而不要等到脚本生成后再添加。因为LoadRunner脚本的可读性并不好,在录制完的脚本中添加事务定义的难度会很大。
在录制过程中,直接添加事务操作也很简单,主要包括如下三步:
在开始执行GUI操作前,先点击图2中的“事务开始”按钮并填写事务名称;
执行GUI操作;
操作完成后,点击图2中的“事务结束”按钮。
这样你刚才执行GUI操作的脚本就会被lr_start_transaction(“事务名称”)和lr_end_transaction(“事务名称”,LR_AUTO)包围起来,也就完成了添加事务的定义。
步骤3:完善录制得到的脚本
脚本录制,只是虚拟用户脚本开发中最简单的一步。我在上一次分享《无实例无真相:基于LoadRunner实现企业级服务器端性能测试的实践(上)》时,提到由Virtual User Generator模块录制的脚本不能直接使用,我们还需要对录制的脚本做以下处理:
这4步处理操作是虚拟用户脚本开发中最关键的地方,你不仅需要知道为什么要进行这些处理,更要能够完成这些处理,否则你录制的脚本无法成功回放。
第一,在两个事务之间加入思考时间
什么是思考时间呢?
用户在实际使用系统时,并不会连续不断地向后端服务器发起请求,在两次发起请求之间往往会有一个时间的间隔,这个时间间隔主要来自于两个方面:
所以,为了让虚拟用户脚本能够更真实地模拟实际用户的行为,我们就需要在两个事务之间加入一定的等待时间。这个等待时间,就是LoadRunner中的思考时间。
你只要直接调用LoadRunner提供的lr_think_time()函数,就可以在两个事务之间加入思考时间。但是,这个思考时间到底设置为多少,并没有那么容易知道。思考时间往往会涉及多方面的因素,严格计算的话会非常复杂。
所以,在实际项目中,一般先粗略估计一个值(比如15 s),然后在实际执行负载场景的过程中,再根据系统吞吐量调整。
你在后续调整思考时间时,无需逐行修改虚拟用户脚本代码,可以在Run-time Settings(运行时设置)中很方便地完成。如图3所示,Run-time Settings中支持多种方式调整思考时间。
第二,对界面输入的数据做参数化操作
数据的参数化,其实很好理解,我再给你举个例子,你马上就能明白。
假设,你录制的虚拟用户脚本完成的是用户登录操作,那么由于脚本回放时需要支持多用户的并发,所以必须要把脚本中的用户名和密码独立出来,放入专门的数据文件中,然后在这个文件中提供所有可能被用到的用户名和密码。
有没有感觉这个概念很熟悉,它其实和我以前介绍到的数据驱动的自动化测试完全相同。
图4给出了参数化配置的界面截图,LoadRunner支持的参数化的数据源很丰富,既可以是excel文件,也可以是数据库中的表等。
这里需要特别说明的是,凡是参数文件中使用的测试数据都需要在执行性能测试前,在被测系统中事先准备好。比如,还是以用户登录的脚本为例,假定你的参数文件中提供了5000个用于并发执行的用户信息,那么这5000个用户必须是已经实际存在于系统中的,这就要求你要在开始测试前事先准备好这5000个用户。
所以,参数化操作其实由两部分组成:
性能测试脚本和测试数据的分离;
事先建立性能测试的数据。
也就是说,参数化的过程往往与性能测试数据准备密不可分。
第三,完成脚本的关联操作
关联操作,是LoadRunner虚拟用户脚本开发过程中最关键的部分,直接关系到脚本是否可以回放成功。
从概念上讲,关联的主要作用是,取出前序调用返回结果中的某些动态值,传递给后续的调用。是不是听起来很拗口,不太好理解?我们来看一个具体的例子吧。
假设,每次客户端连接服务器端时,服务器端都会用当前的时间戳(Time Stamp)计算CheckSum,然后将Time Stamp和CheckSum返回给客户端。然后,客户端就把Time Stamp + CheckSum的组合作为唯一标识客户端的Session ID。录制脚本时,录制得到的一定是硬编码(hardcode)的Time Stamp值和CheckSum值。
图5展示了这个交互过程,录制得到Time Stamp的值是TS,而CheckSum的值是CS。
采用Time Stamp + CheckSum的组合作为Session ID的方式,在我们回放这个脚本的时候就有问题了。因为回放时,这段硬编码已经有了新的Time Stamp值和CheckSum值,并且显然与之前的值不同,所以服务器无法完成Session ID的验证,也就导致了脚本回放失败。
其实,这种情况几乎存在于所有的虚拟用户脚本中,所以我们必须要解决这个问题。
解决方法就是,在脚本回放的过程中,实时抓取Time Stamp值和CheckSum值,然后用实时抓取到的值替换后续需要使用这两个值的地方。这个过程就是“关联”。
如图7所示,关联就是解析服务器端的返回结果,抓取新的Time Stamp值和CheckSum值,然后后续的操作都使用新抓取的值,这样脚本就能回放成功了。
理解了关联操作,在脚本中处理关联就比较简单了,LoadRunner提供了功能强大的关联函数web_reg_save_param()。这个关联函数支持多种动态值的获取方式,用得最多的是基于“前序字符串匹配”加上“后续字符串匹配”的方式。其中,字符串匹配,支持正则表达式。
我们一起来看个具体的例子吧。
假设,服务器端返回的结果是“LB=name=timestamp value=8888.LB=name=CheckSum”,那么为了能够获取到“8888”这个动态值,我们就可以用“前序字符串=LB=name=timestamp value=”和“后续字符=.LB=name=CheckSum”来“框出” 8888”这个动态值。
另外,需要特别注意的是web_reg_save_param()函数是注册型函数,必须放在获取动态值所属的请求前面,相当于先声明,后调用。
更多的关联函数用法,你可以参考LoadRunner官方文档。
第四,加入检查点
检查点,类似于功能测试中的断言。但是,性能测试脚本,不像功能测试脚本那样需要加入很多的断言,往往只在一些关键步骤后加入很少量的检查点即可。这些检查点的主要作用是,保证脚本按照原本设计的路径执行。
最常用的检查点函数是web_reg_find(),它的作用是通过指定左右边界的方式“在页面中查找相应的内容”。这里需要注意的是,这个函数也是注册型函数,即需要放在所检查的页面之前,否则会检查失败。更多的检查点函数以及用法也请参考LoadRunner官方文档。
步骤4:验证脚本的正确性
完成了脚本开发后,根据我的个人经验,我强烈建议你按照以下顺序检查脚本的准确性:
以单用户的方式,在有思考时间的情况下执行脚本,确保脚本能够顺利执行,并且验证脚本行为以及执行结果是否正确;
以单用户的方式,在思考时间为零的情况下执行脚本,确保脚本能够顺利执行,并且验证脚本行为以及执行结果是否正确;
以并发用户的方式,在有思考时间的情况下执行脚本,确保脚本能够顺利执行,并且验证脚本行为以及执行结果是否正确;
以并发用户的方式,在思考时间为零的情况下执行脚本,确保脚本能够顺利执行,并且验证脚本行为以及执行结果是否正确。
只有上述四个测试全部通过,虚拟用户脚本才算顺利完成。
至此,我们完成了第二个阶段的“录制并增强虚拟用户脚本”的工作,顺利拿到了虚拟用户脚本。那么接下来,我们就会进入第三个阶段,使用开发完成的虚拟用户脚本创建并定义性能测试场景。
还记得我在分享《工欲善其事必先利其器:后端性能测试工具原理与行业常用工具简介》这个主题时,介绍过的性能测试场景的内容吗?如果有点忘记了,我建议你先回顾一下这篇文章的内容。
这个阶段的工作,就是在LoadRunner Controller中设置性能测试场景。由于整个设置过程,都是基于Controller的图形用户界面的操作,本身没什么难度,所以我就不再详细展开了,如果有这方面的问题,你也可以自行百度或者给我留言。
完成了性能测试场景的设计与定义后,执行性能测试场景就非常简单了。
这个过程一般是在LoadRunner Controller中完成。你可以通过Controller发起测试、停止测试、调整性能测试场景的各种参数,还可以监控测试的执行过程。
执行完性能测试后,LoadRunner会根据自己的标准并结合性能测试场景中定义的系统监控器指标,生成完整的测试报告。在Analysis中,不仅可以以图形化的方式显示单个指标,也可以将多个指标关联在一起进行比较分析。
图8展示了使用LoadRunner Analysis展示事务平均响应时间的界面,我们可以看到图片右下角各个事务的最小响应时间、最大响应时间和平均响应时间。
性能测试报告的分析,是一项技术含量非常高的工作。优秀的性能测试工程,通过报告中的数值以及数值之间的相互关系,就能判断出系统中可能存在的问题。这就好比医生看验血报告,经验丰富的医生可以根据验血报告对病情做出八九不离十的判断。
性能测试报告的解读,需要丰富的系统架构、性能理论以及大量实战经验的积累。这个话题已经超出了我今天要分享的范围,所以我也就不再继续展开了。
今天接着上一篇文章,我和你分享了企业级后端性能测试的后四个阶段的内容,包括录制并增强虚拟用户脚本、创建并定义性能测试场景、执行性能测试场景,以及分析测试报告。现在,我再为你总结一下每一个阶段的重点内容。
录制并增强虚拟用户脚本,这个阶段的工作又可以分为识别被测应用使用的协议、录制脚本、完善录制得到的脚本、验证脚本的正确性四步。其中,完善录制得到的脚本这一步,涉及到了很多概念和基础知识,所以我进行了重点讲解,希望帮你克服性能测试的难点。
创建并定义性能测试场景,以及执行性能测试场景,这两个阶段的工作都是在LoadRunner的Controller模块中完成的,也都比较简单。你可以参考我在《工欲善其事必先利其器:后端性能测试工具原理与行业常用工具简介》这篇文章分享的内容,完成这两个阶段的工作。
分析测试报告,这个工作的技术含量非常高。深入解读性能测试报告的能力,需要丰富的系统架构、性能理论,以及大量实战经验。所以,我们需要在平时工作中,不断地丰富自己的知识体系。
你们公司的性能测试是否使用LoadRunner,在使用过程中遇到了什么难题?你们又是如何解决的呢?
感谢你的收听,欢迎你给我留言。
评论