33 无实例无真相:基于LoadRunner实现企业级服务器端性能测试的实践(下) 你好,我是茹炳晟。今天我和你分享的主题是:无实例无真相之基于LoadRunner实现企业级服务器端性能测试的实践(下)。

今天,我会继续和你分享如何基于LoadRunner完成企业级服务器端的性能测试。通过我上一次的分享,你已经清楚知道了,整个性能测试过程可以分为五个阶段,并且解决了整个测试过程中最难的一部分工作,即如何获取具体的性能测试需求。

现在,我们先来回顾一下,性能测试包含的五个阶段:性能需求收集以及负载计划制定、录制并增强虚拟用户脚本、创建并定义性能测试场景、执行性能测试场景,以及分析测试报告。所以,今天,我们就要解决剩下的4个阶段的问题了。

阶段2:录制并增强虚拟用户脚本

我已经在上篇文章中和你提到,完成了性能测试需求分析后,你就已经明确了要开发哪些性能测试脚本。现在,我们就一起来看看开发性能测试脚本的步骤,以及相关的技术细节。

从整体角度来看,用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给出的建议录制协议界面。

图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)包围起来,也就完成了添加事务的定义。

图2 Virtual User Generator的脚本录制控制条

步骤3:完善录制得到的脚本

脚本录制,只是虚拟用户脚本开发中最简单的一步。我在上一次分享《无实例无真相:基于LoadRunner实现企业级服务器端性能测试的实践(上)》时,提到由Virtual User Generator模块录制的脚本不能直接使用,我们还需要对录制的脚本做以下处理:

  • 在两个事务之间加入思考时间(Think Time);
  • 对界面输入的数据做参数化(Parameterization)操作;
  • 完成脚本的关联(Correlation)操作;
  • 加入检查点(Check Point)。

这4步处理操作是虚拟用户脚本开发中最关键的地方,你不仅需要知道为什么要进行这些处理,更要能够完成这些处理,否则你录制的脚本无法成功回放。

第一,在两个事务之间加入思考时间

什么是思考时间呢?

用户在实际使用系统时,并不会连续不断地向后端服务器发起请求,在两次发起请求之间往往会有一个时间的间隔,这个时间间隔主要来自于两个方面:

  • 一是,用户操作的人为等待时间,因为用户不可能像机器人那样快速地执行操作;
  • 二是,用户可能需要先在页面上填写很多信息后之后,才能提交操作,那么填写这些信息就需要花费一定的时间。

所以,为了让虚拟用户脚本能够更真实地模拟实际用户的行为,我们就需要在两个事务之间加入一定的等待时间。这个等待时间,就是LoadRunner中的思考时间。

你只要直接调用LoadRunner提供的lr_think_time()函数,就可以在两个事务之间加入思考时间。但是,这个思考时间到底设置为多少,并没有那么容易知道。思考时间往往会涉及多方面的因素,严格计算的话会非常复杂。

所以,在实际项目中,一般先粗略估计一个值(比如15 s),然后在实际执行负载场景的过程中,再根据系统吞吐量调整。

你在后续调整思考时间时,无需逐行修改虚拟用户脚本代码,可以在Run-time Settings(运行时设置)中很方便地完成。如图3所示,Run-time Settings中支持多种方式调整思考时间。

图3 通过Run-time Settings统一调整思考时间

  • As recorded,代表的是直接使用lr_think_time()函数中指定的时间。
  • Mutiply recorded think time by,代表的是在lr_think_time()函数中指定的时间基础上乘以一个数字。比如这个数字是2,那么所有的思考时间都会翻倍。
  • Use random percentage of recorded think time,指的是使用指定思考时间范围内的随机值。例如,如果lr_think_time()函数中指定的时间是2 s,并且指定最小值为50%,最大值为200%,则实际的思考时间会取最小值1 s(2 s_50%)和最大值4 s(2 s_200%)之间的随机值。
  • Limit think time to,指的是为思考时间设置一个上限值,只要lr_think_time()函数中指定的时间没有超过这个上限值,就按照lr_think_time()函数指定的值,如果超过了就取这个上限值作为思考时间。

第二,对界面输入的数据做参数化操作

数据的参数化,其实很好理解,我再给你举个例子,你马上就能明白。

假设,你录制的虚拟用户脚本完成的是用户登录操作,那么由于脚本回放时需要支持多用户的并发,所以必须要把脚本中的用户名和密码独立出来,放入专门的数据文件中,然后在这个文件中提供所有可能被用到的用户名和密码。

有没有感觉这个概念很熟悉,它其实和我以前介绍到的[数据驱动的自动化测试]完全相同。

图4给出了参数化配置的界面截图,LoadRunner支持的参数化的数据源很丰富,既可以是excel文件,也可以是数据库中的表等。

图4 虚拟用户脚本参数化配置的界面截图

这里需要特别说明的是,凡是参数文件中使用的测试数据都需要在执行性能测试前,在被测系统中事先准备好。比如,还是以用户登录的脚本为例,假定你的参数文件中提供了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。

图5 关联原理图-脚本录制过程

采用Time Stamp + CheckSum的组合作为Session ID的方式,在我们回放这个脚本的时候就有问题了。因为回放时,这段硬编码已经有了新的Time Stamp值和CheckSum值,并且显然与之前的值不同,所以服务器无法完成Session ID的验证,也就导致了脚本回放失败。

图6 关联原理图-脚本回放过程

其实,这种情况几乎存在于所有的虚拟用户脚本中,所以我们必须要解决这个问题。

解决方法就是,在脚本回放的过程中,实时抓取Time Stamp值和CheckSum值,然后用实时抓取到的值替换后续需要使用这两个值的地方。这个过程就是“关联”。

如图7所示,关联就是解析服务器端的返回结果,抓取新的Time Stamp值和CheckSum值,然后后续的操作都使用新抓取的值,这样脚本就能回放成功了。

图7 关联原理图-使用“关联”后的脚本回放过程

理解了关联操作,在脚本中处理关联就比较简单了,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:验证脚本的正确性

完成了脚本开发后,根据我的个人经验,我强烈建议你按照以下顺序检查脚本的准确性:

  • 以单用户的方式,在有思考时间的情况下执行脚本,确保脚本能够顺利执行,并且验证脚本行为以及执行结果是否正确;
  • 以单用户的方式,在思考时间为零的情况下执行脚本,确保脚本能够顺利执行,并且验证脚本行为以及执行结果是否正确;
  • 以并发用户的方式,在有思考时间的情况下执行脚本,确保脚本能够顺利执行,并且验证脚本行为以及执行结果是否正确;
  • 以并发用户的方式,在思考时间为零的情况下执行脚本,确保脚本能够顺利执行,并且验证脚本行为以及执行结果是否正确。

只有上述四个测试全部通过,虚拟用户脚本才算顺利完成。

至此,我们完成了第二个阶段的“录制并增强虚拟用户脚本”的工作,顺利拿到了虚拟用户脚本。那么接下来,我们就会进入第三个阶段,使用开发完成的虚拟用户脚本创建并定义性能测试场景。

阶段3:创建并定义性能测试场景

还记得我在分享《工欲善其事必先利其器:后端性能测试工具原理与行业常用工具简介》这个主题时,介绍过的性能测试场景的内容吗?如果有点忘记了,我建议你先回顾一下这篇文章的内容。

这个阶段的工作,就是在LoadRunner Controller中设置性能测试场景。由于整个设置过程,都是基于Controller的图形用户界面的操作,本身没什么难度,所以我就不再详细展开了,如果有这方面的问题,你也可以自行百度或者给我留言。

阶段4:执行性能测试场景

完成了性能测试场景的设计与定义后,执行性能测试场景就非常简单了。

这个过程一般是在LoadRunner Controller中完成。你可以通过Controller发起测试、停止测试、调整性能测试场景的各种参数,还可以监控测试的执行过程。

阶段5:分析测试报告

执行完性能测试后,LoadRunner会根据自己的标准并结合性能测试场景中定义的系统监控器指标,生成完整的测试报告。在Analysis中,不仅可以以图形化的方式显示单个指标,也可以将多个指标关联在一起进行比较分析。

图8展示了使用LoadRunner Analysis展示事务平均响应时间的界面,我们可以看到图片右下角各个事务的最小响应时间、最大响应时间和平均响应时间。

图8 性能测试报告的分析

性能测试报告的分析,是一项技术含量非常高的工作。优秀的性能测试工程,通过报告中的数值以及数值之间的相互关系,就能判断出系统中可能存在的问题。这就好比医生看验血报告,经验丰富的医生可以根据验血报告对病情做出八九不离十的判断。

性能测试报告的解读,需要丰富的系统架构、性能理论以及大量实战经验的积累。这个话题已经超出了我今天要分享的范围,所以我也就不再继续展开了。

总结

今天接着上一篇文章,我和你分享了企业级后端性能测试的后四个阶段的内容,包括录制并增强虚拟用户脚本、创建并定义性能测试场景、执行性能测试场景,以及分析测试报告。现在,我再为你总结一下每一个阶段的重点内容。

录制并增强虚拟用户脚本,这个阶段的工作又可以分为识别被测应用使用的协议、录制脚本、完善录制得到的脚本、验证脚本的正确性四步。其中,完善录制得到的脚本这一步,涉及到了很多概念和基础知识,所以我进行了重点讲解,希望帮你克服性能测试的难点。

创建并定义性能测试场景,以及执行性能测试场景,这两个阶段的工作都是在LoadRunner的Controller模块中完成的,也都比较简单。你可以参考我在《工欲善其事必先利其器:后端性能测试工具原理与行业常用工具简介》这篇文章分享的内容,完成这两个阶段的工作。

分析测试报告,这个工作的技术含量非常高。深入解读性能测试报告的能力,需要丰富的系统架构、性能理论,以及大量实战经验。所以,我们需要在平时工作中,不断地丰富自己的知识体系。

思考题

你们公司的性能测试是否使用LoadRunner,在使用过程中遇到了什么难题?你们又是如何解决的呢?

感谢你的收听,欢迎你给我留言。

参考资料

https://learn.lianglianglee.com/%e4%b8%93%e6%a0%8f/%e8%bd%af%e4%bb%b6%e6%b5%8b%e8%af%9552%e8%ae%b2/33%20%e6%97%a0%e5%ae%9e%e4%be%8b%e6%97%a0%e7%9c%9f%e7%9b%b8%ef%bc%9a%e5%9f%ba%e4%ba%8eLoadRunner%e5%ae%9e%e7%8e%b0%e4%bc%81%e4%b8%9a%e7%ba%a7%e6%9c%8d%e5%8a%a1%e5%99%a8%e7%ab%af%e6%80%a7%e8%83%bd%e6%b5%8b%e8%af%95%e7%9a%84%e5%ae%9e%e8%b7%b5%ef%bc%88%e4%b8%8b%ef%bc%89.md