You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

247 lines
18 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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