☰
LoadRunner VuGen脚本开发全流程:录制、关联、参数化与压测排障实战
2026/10/21 16:10:51 网站建设 项目流程

1. VuGen到底在性能测试里扮演什么角色:先搞懂脚本的本质

先说点实的。很多人一接触LoadRunner,第一步就是打开Virtual User Generator(简称VuGen),但绝大多数人只是机械地跟着录制、回放、跑场景,压根没想过VuGen在整个性能测试链条里到底站在哪个位置。这么说吧,压测脚本就是整个性能测试的地基,VuGen就是造这块地基的机器。机器不好用、地基没打牢,后面Controller跑出来的所有TPS、响应时间、错误率数据全是空中楼阁。

我见过不少团队,问题排查了大半天,最后发现是脚本里一个变量没做关联,导致每个虚拟用户都在用同一条数据请求服务端,服务端查不到就返回异常,压测结果自然一塌糊涂。这类问题绝对不是个别现象,而是脚本开发阶段埋下的雷。所以这篇文章我会围绕VuGen脚本开发的全流程,把录制前的准备、脚本改造、运行设置、场景联调、报错排查几个关键环节全部过一遍。

这篇文章适合谁看?刚入行的性能测试工程师、需要自己维护压测脚本的自动化测试同学,以及那些已经用LoadRunner跑过几次场景但始终没搞懂脚本细节的人。读完你应该能回答三个问题:脚本里的每个函数是干什么的?哪些地方必须改而不是录完就能用?遇到报错时怎么快速定位是自己脚本的问题还是环境的问题。

要理解VuGen,先得理解它的工作逻辑。它的核心能力是录制和回放:录制阶段把你手动操作业务流程时的客户端与服务端通信内容全部记录下来,生成一份C语言风格的脚本骨架;回放阶段再模拟这些请求,检查服务端是否正常响应。本质上,它是一个“协议层”的工具,捕获的不是界面上的鼠标点击,而是底层报文。这也是为什么用VuGen录制脚本时,我们不太关心页面长什么样,更关心走了什么协议、发了什么请求。

这种设计带来的直接好处是,即使服务端界面怎么改,只要接口协议没变,脚本照跑不误。坏处也很明显:录出来的脚本是偏底层的,充满了服务端生成的动态数据、硬编码的参数,直接拿去做压测根本不行。这也是本文要说透的——真正的脚本开发,重点不在于“录制”这个动作,而在于录制之后的二次改造。

2. 录制前的三项清理工作:决定脚本质量的第一道关口

2.1 先选对协议,再谈其他

录制VuGen脚本的第一步是选择协议,很多人在这里就图省事,直接选“Web - HTTP/HTML”就上手录。大多数B/S系统确实是用这个,但如果你录的是C/S架构客户端,或者涉及Socket、WebService的接口,选错协议就会录出大量看不懂的乱码请求,甚至什么都没录到。

我一般会建议新人在录制前先去翻一下被测系统的运维文档。确认系统的前后端交互方式、接口类型,再在VuGen新建脚本时打开“多协议”窗口把需要用到的协议都勾上。如果拿不准,就先用“Web - HTTP/HTML”试录十分钟,看生成的脚本里有没有看起来像业务操作的请求。如果全是无关的握手信息或者页面静态资源请求,基本可以判断协议选得不对。

这里补充一个经验:现在很多系统的前端是HTTPS,内部带了各种证书校验和SSL握手逻辑。录制时如果没在VuGen的录制选项里配置好证书相关内容,录制过程会反复失败,或者录出来的脚本回放时直接提示证书错误。所以录制前先确认测试机能否正常访问被测系统的所有依赖域名,同时也确认测试机本地的时间和被测服务器时间一致。你可能会觉得这是小事,但SSL证书校验对时间敏感,时间偏差超过一定范围回放必挂。

2.2 URL过滤必须做,否则脚本会被垃圾请求淹没

说句不太好听的,现在很多前端页面背后挂了一堆统计、埋点、第三方资源请求。如果录制时不设置URL过滤,录出来的脚本里可能有一堆GET /log/track.jsp、/static/js/xxxx.js之类的垃圾请求。这些请求在脚本回放时不是导致报错,就是白白消耗服务器资源,干扰你对业务请求结果的判断,更坑的是可能导致压测场景里TPS虚高。

所以在录制之前,我会在Recording Options里设置URL过滤规则。把那些静态资源的后缀(.js、.css、.png、.jpg等)直接排除;再把和业务无关的第三方域名、埋点域名加进排除列表。这样录出来的脚本会比较干净,后面脚本改造时也能聚焦在核心业务流程上。这一步不是在偷懒,而是在控制压测流量模型的有效性。

有人可能会问,静态资源不录会不会导致压测结果不准确?这要分情况。如果你压测的目的是验证业务接口的并发能力,那静态资源本来就不该进模型,因为它们是浏览器侧的并发行为,不是业务操作行为。如果你的压测目标是全链路仿真,包括前端资源加载的瓶颈,那静态资源请求也应该包含进去,只是需要单独进行流量配比,而不是让VuGen一股脑录进去随机访问。我个人的做法是:压测业务接口时过滤掉静态资源,需要全链路压测时用多脚本单独构造资源请求模型。

2.3 录制模式选择:别一上来就点Record

VuGen提供多种录制模式:一种基于代理,一种基于端口,还有一种是基于网络层的抓包。其中代理模式是比较好用也最常见的选择,它会在你的测试机上起一个本地代理,浏览器走这个代理访问被测系统,VuGen把这些报文解析成脚本。这个模式的好处是不需要额外装任何客户端组件,坏处是依赖浏览器代理设置,浏览器更新后偶尔会遇到代理失效的问题。

如果你录制的对象是客户端程序或移动App,代理模式往往就不适用了,这时候需要用“端口映射”或者安装移动端的录制证书才能抓到包。我遇到过不少测试同事,在Windows上录桌面客户端,结果发现代理模式根本拦不到包,后来还是换成了端口录制才解决。所以录制前先明确对象:B/S系统优先代理模式,C/S和移动端考虑端口或专用方案。

选好模式只是第一步,录制进去之后要把操作节奏调整好。录制用例时要特别注意,不要在页面上停留太长时间思考下一步点什么,因为思考时间也会被当成脚本内容录制进去。这不是说思考时间没用,而是录制阶段应该尽量减少无关的等待,避免脚本里出现超长think time,影响后续对业务耗时的判断。录制期间我还有个习惯:操作一步,心里记一步,大致清楚脚本里会生成哪些请求,这样后期脚本审查时能快速判断有没有录多或者录漏。

3. 录制后的脚本结构拆解:看懂函数才能动手改

3.1 典型脚本的骨架长什么样

用Web - HTTP/HTML协议录一个最简单的登录+查询业务,生成的脚本通常包括这几类内容:vuser_init、Action、vuser_end这三个默认分区,以及一堆web_url、web_submit_data、web_reg_find之类的函数。初学者看到这些函数容易发懵,其实它们并不难理解。

vuser_init是虚拟用户初始化时执行的脚本段,适合放登录这类前置操作;Action部分是业务主体,会被反复迭代执行;vuser_end用于清理工作,比如退出登录。场景运行时,每个虚拟用户先跑一遍vuser_init,然后循环执行Action部分,最后执行vuser_end。这个结构决定了你在写脚本时要考虑好:登录放哪里,业务操作放哪里。

我看到很多新手写的脚本,把所有请求全堆在vuser_init里,然后在场景里设置迭代100次,结果每个用户压测时一直在循环登录,这肯定有问题。用户登录通常只做一次,查询、下单、提交这类核心业务操作才是循环的主体。所以录制完第一步,就得按业务语义把脚本段重新归类。

再说到函数。web_url用来发起一次GET请求,通常用于获取页面;web_submit_data用来提交表单;web_custom_request是最灵活的,可以定义任意格式的请求报文,常用于接口级别的压测。这几个函数基本覆盖了90%的HTTP协议录制场景。开发脚本时,你不需要背下所有函数,但看到这些函数时要能判断它是发了一次什么类型的请求、传了什么参数。

3.2 为什么录完不能直接用:从回放成功到压测可用的距离

录制完脚本,第一件事肯定是点回放看是否成功。很多人在这一步看到日志提示“lready already exist”或者“错误码”就不知道下一步怎么办了。比较常见的坑是,服务端在每次操作时都会生成会话ID、时间戳或者随机数据,这些数据在录制时是写死在脚本里的。回放时如果原样使用这些写死的数据,服务端会认为请求非法,于是报错或者跳转到错误页面。

这就需要做“关联”。关联本质上是把服务端返回的动态数据提取出来,存成变量,再在后续请求中替换掉写死的部分。LoadRunner有自动关联功能,但我必须说一句,自动关联很多时候并不可靠,它会漏掉关键的动态数据,或者关联了不该关联的内容。更靠谱的做法是结合录制日志按需手动处理:第一次回放失败后,回看日志,找到请求和响应中变化的部分,再针对性地做关联。

另外,回放“成功”也不代表脚本就真的可用。LoadRunner的“成功”只是说请求发送出去并收到了响应,不代表业务结果正确。比如登录后刷出的用户信息是空的,或者提交订单后服务端返回了“参数缺失”的提示,这些都可能在回放日志里被当成正常响应。所以脚本回放完后一定要验证业务结果,可以通过添加检查点来校验页面或接口返回是否包含预期的业务关键词。

4. 脚本开发的三大核心改造:事务、参数化、关联

4.1 事务(Transaction):给性能指标划好边界

性能测试最常看的指标是TPS和响应时间,但一台服务器同时被测很多接口,怎么知道某个接口到底花了多久?这就需要事务。事务是脚本里的一段标记,把业务流程中的某一段操作括起来,在结果分析时单独统计这一段操作的响应时间、吞吐量等指标。

用事务函数很简单,在请求前面加lr_start_transaction("事务名"),在请求结束之后加lr_end_transaction("事务名", LR_AUTO)。但这里有几个关键点。

第一个是事务名的命名规范。我见过脚本里几百个事务都叫Action或者T01、T02,结果Controller跑完根本分不清哪个是登录、哪个是查询。光给“性能分析”和“问题定位”带来的麻烦就够你喝一壶的。我个人习惯按“模块_功能_动作”的格式命名,比如Login_Submit、Order_Query、Pay_Confirm,一眼能看出这是什么操作。

第二个是事务的边界要恰好覆盖被测操作,而不是整个脚本。有些同事图省事,直接在vuser_init里放一个事务把登录包进去,在Action里再放一个大事务把所有业务请求全包起来。这么做不是不行,但粒度太粗,压测结果里你只能看到整段流程的耗时,定位不到具体是哪一步拖了后腿。

第三个是事务的判断标准。默认LR_AUTO会根据请求是否报错自动判断事务成功还是失败。但有些业务是“假失败”,比如服务端返回200,但页面提示“库存不足”,从协议层看响应成功,从业务层看事务是失败的。遇到这种情况,可以配合检查点函数判断业务结果,再用lr_end_transaction("事务名", LR_FAIL)标记事务为失败。这样Controller得到的错误数和失败数才真正反映业务问题。

4.2 参数化(Parameterization):模拟真实用户行为的关键

压测的目的是模拟大量真实用户同时操作,但真实用户之间是有差异的:有人用账号A,有人用账号B,查询的关键字也会不一样。如果脚本里所有虚拟用户都用同一个账号、同一份数据,那就相当于拿一个用户把服务器压垮,既测不出问题也可能触发一些逻辑保护,结果根本不可信。解决这个问题的手段就是参数化。

参数化是用一个可变化的“参数”替换脚本中固定的字段值。举例来说,登录脚本里通常有用户名和密码,录制时是某个指定账号,开发脚本时我把用户名设为参数Username,参数的数据源指向一个包含几十个测试账号的文件,这样每个虚拟用户取到的用户名都不一样。

做参数化时,选定参数只是开始,关键在取值策略。LoadRunner里参数化最经常设置的几个属性如下表所示:

属性取值策略适用场景
Select next rowSequential(顺序)要求每个虚拟用户取到唯一值时可以选择,但用户数超过数据量会取完后又从头取
Random(随机)无状态查询场景,任意取值不影响业务时用随机最方便
Unique(唯一)账号类、凭证类数据必须确保不重复时使用
Update value onEach occurrence(每次出现)同一参数在迭代中多次被引用且每次都要变化时用这个
Each iteration(每次迭代)同一个脚本循环中参数值保持不变,下一轮迭代才变化,适用登录这类操作

很多人在参数化文件准备上栽跟头。录制时把数据写死在脚本里,开发脚本时用Excel准备了几百行测试数据,结果压测开始时大量用户报错,一看原因,原来是数据文件里混着重复账号,或者文件编码有问题导致中文参数乱码。这个提醒你:参数数据文件准备好后,先做个查重和格式校验,不要等到场景跑挂了才回头看。

关于参数化的边界,还有一点值得说。参数化不是越多越好。把不该参数化的值也改掉,反而可能破坏业务一致性。比如同一个业务流程中有两个请求都引用同一份单据ID,这种情况下如果都做成随机取值,两个请求各取各的ID,服务端就会校验失败。遇到这种场景,参数化时必须保证多次引用取到同一个值,需要在参数设置里把“每次迭代更新一次”勾上,确保同一迭代内签名、单号这类关键数据保持一致。

4.3 关联(Correlation):处理动态数据不能靠蛮力

接着前面说的关联问题展开。关联是VuGen脚本开发里最考验耐心的一步,因为自动关联的识别率不稳定,遇到复杂的加密参数、签名参数,往往会漏掉。

处理关联我一般这么操作:先跑一次回放,在回放日志里找到请求失败或业务结果异常的位置,再对比录制快照和回放快照,看看响应报文里哪些字段是变化的。找到以后,用web_reg_save_param函数把响应中的动态值提取成一个参数,放在后续请求前面引用。

写web_reg_save_param时有几个参数要特别注意:第一个是响应内容中要找的内容,边界写法用左边界(LB)和右边界(RB)来框定;第二个是实例序号(Ordinal),如果同一个界面有多处返回相同格式的数据,要指明取第几个;第三个是保存到数组还是单个变量。边界写得太窄,提取不到值;太宽,会把一堆无关内容裹进来,后续请求的数据就乱了。

在实际项目里,服务端有时会返回一个很长的JSON串,里面的动态字段嵌套在数据结构深层。这时直接写左右边界会很痛苦。我的做法是抓取这个JSON串的某个唯一标记作为锚点,用通配匹配出整串JSON,再用后续的字符串处理函数从变量中再次截取目标字段。这一步看起来绕,但实际上比反复调试边界要可靠得多。

还有一类关联是因为请求本身带了签名,比如业务接口要求前端对请求参数做MD5加密拼上时间戳。录制时的时间戳和签名都是固定的,回放时服务端一校验就拒绝。这种场景就不能靠录制+关联解决了,而是要在脚本里自己生成签名逻辑。处理方法是使用LoadRunner自带的加密函数或直接写C代码来计算签名参数,再把计算结果赋给请求头或请求体。这类改造比较偏开发,但掌握了之后很多签名接口的压测都能做。

这里说一个我自己的操作习惯:每做完一次关联或参数化修改,都单独回放一次并查看日志确认修改生效,而不是攒了一堆修改再一起回放。这样出了问题能快速定位是在哪一次修改引入的,排查时间能省下一大半。

5. 场景联调前的脚本设置与验证:跑得通不代表压得住

5.1 运行时设置(Run-Time Settings)里那些决定压测质量的项目

脚本开发完,回放成功率高,这只是第一步。压测场景里跑起来是否稳定,还取决于运行时设置。Vuser -> Run-Time Settings里几个关键项要仔细过一遍。

首先是最重要的“思考时间(Think Time)”。脚本录制时会记录你在页面停留、输入的时间,回放时默认也会模拟这些等待。做性能压测时,思考时间需要根据模型来决定:如果压测目标是验证系统能承受的最大并发能力,通常会把思考时间设为“忽略”,让虚拟用户不间断地发请求;如果目标是模拟真实用户访问压力,则应该按权重设定思考时间范围,也可以在场景里使用百分比来分布思考时间的长短。

其次是迭代次数。场景模式里一般不在这里设置,迭代次数通常由Controller的Duration(持续时间)控制。但在脚本调试阶段,你想快速验证脚本是否稳定,可以把迭代次数设成5~10次跑一遍,确认连续多次回放不报错再放场景。

然后是日志设置。调试阶段开启扩展日志可以定位问题;但正式压测时日志开关必须关掉或者调低级别,否则写日志本身就消耗磁盘I/O和CPU资源,结果数据会被污染。特别要提醒的是“日志文件大小限制”,压测时间长的项目如果日志默认无限增长,磁盘被写满之后会引发连锁问题。正式压测前统一检查一下这台机器磁盘剩余空间。

还有一些设置项是关于超时时间的:连接超时、HTTP请求超时和接收超时。默认值有时太短,压测过程中一旦服务器CPU飙高,个别请求稍微慢一点就被判断为超时,会看到大量超时错误,但服务器其实没有真的挂掉。我会在场景设计前根据被测系统的平均响应时间把超时时间适度放宽,一般是平均响应时间的两到三倍,避免误报。

5.2 集合点(Rendezvous)用还是不用,要看压测意图

集合点不是VuGen脚本里必须有的东西,但它在某些压测场景中绕不开。集合点的作用是把一批虚拟用户同时“拦住”,等用户数达到设定值后一起释放,形成瞬间并发冲击,比如模拟1万人同时秒杀、同时抢券这种场景。

写集合点只需要在脚本对应操作前加lr_rendezvous("集合点名")。但有几个容易踩坑的点。第一,集合点要与场景里的用户数、并发策略搭配使用。Controller场景里如果用户是每秒逐渐增加上来的,集合点多半集不齐,因为先到的用户等了很久,后被释放,并发效果就会打折扣。第二,集合等待时间设置不当。默认集合点会一直等到用户集齐才放行,如果场景里某个用户掉线了,后面所有人都要卡在集合点上,压测就“假死”了。建议给集合点设置一个超时时间,比如超过3秒就放行当前已到用户,保证压测能继续跑。

第三,集合点实际上会让所有虚拟用户在同一时刻发送请求,对服务器造成突发压力非常真实,但对监控数据的影响也很明显。我看到不少人一套集合点压测跑完,只看平均响应时间,结果发现平均响应时间反而低了,因为所有请求同时打进来时大量排队,实际体验并没有变好。研究结果时要把集合点发生时刻的数据切片单独看,而不是混在一起平均。

5.3 场景联调前的最终验证清单

脚本开发到了最后阶段,我会按清单跑一遍验证,确认没问题才交给Controller做场景配置。清单内容大概是:

  • 用5~10个虚拟用户,迭代10次以上回放,检查是否稳定、有没有偶发报错。
  • 业务结果是否真的正确:登录后能拿到会话、查询有数据返回、提交后状态变化是否符合预期。
  • 事务延时是否合理、事务通过率是否接近100%。
  • 检查脚本里有没有调试时的输出函数(比如lr_output_message打印大量调试信息)残留,压测前必须清掉。
  • 确认参数文件路径有效,读取权限正常;脚本在无界面模式下能正常运行。
  • 检查场景运行时每个用户占用的资源量,预判最大并发上限,避免单机负载时资源不足影响结果准确性。

这套清单看起来简单,但它能帮你把80%的脚本问题挡在场景压测之前。如果脚本带着问题进了Controller,压测跑两小时才发现数据无效,那才是真的欲哭无泪。

6. 常见报错与现场排查技巧实录

6.1 日志与返回码:定位问题首先要养成的习惯

VuGen脚本报错的排查,很多时候是分析日志的过程。LoadRunner的回放日志可以按级别展示请求与响应细节,重点看两个地方:扩展日志里的“服务器返回”和“请求体”。看到异常返回码时,先别看花了,直接把脚本里对应函数前后的参数值、返回报文拉出来对比。

这里举一个典型的例子:查询接口回放时报“400 Bad Request”,日志里有一大段URL和被转义的参数。很多人第一反应去改请求头,其实把请求URL解码出来一看,发现是参数里的某个字段值带了空格、中文没做URL编码。这类问题排查时用“对比法”非常有效:打开录制时的日志,找到当时的请求体,跟你这份回放日志里的请求体做逐字对比,差异点就是问题所在。

再说一种常见报错:“Error: -27995: Requested object not found”。这个错误码往往和前面讲的静态资源过滤有关。如果你的URL过滤把页面里的某些资源排除了,但脚本回放时某个动态参数引用了这个资源的内容,就会找不到。解决办法还是回看脚本,排查引用来源,而不是一味加“事后检查函数”。

6.2 回放期间遇到的典型问题速查表

报错提示常见原因排查思路
Error -27796: Failed to connect to server被测服务端口不通、网络不通、连接超时设置太短先telnet或curl验证连通性,再检查IP/端口是否被访问控制拦截
Error -27727: Step download timeoutresponse太大、下载时间超过了HTTP超时设置调大HTTP接收超时时间,同时检查服务器是否有大报文返回
Error -27492: Http send request failed请求体格式异常、SSL握手失败检查代理设置和证书配置,或对比录制快照中的请求格式
Warning: The string xxx not found关联或检查点没匹配到内容细化关联取值边界,检查返回的报文是否被截断
Error: Missing or empty argument参数数据文件为空或者取值越界检查参数文件与取值策略,确认迭代次数与数据量匹配
Transaction failed事务状态收到LR_FAIL或者请求内部报错看事务失败的具体请求,拆开事务边界逐段定位

这张表不是万能的,但涵盖了日常VuGen使用中最常见的一批问题。真遇到特殊场景,建议遵循“由简到繁”的排查原则:先确认网络链路和被测服务状态,再看脚本自身代码,最后才考虑是LoadRunner本身的限制或环境问题。

6.3 三个让排查效率翻倍的经验

第一个经验是“交叉对比”。不管报什么错,先把回放失败的那份日志和录制时的原始快照放到一起对比。LoadRunner提供了比较录制与回放功能的机制,用起来能很快找出脚本偏差。这条方法解决了我实实在在遇到的很多疑难杂症。

第二个经验是“换工具验证”。遇到HTTP接口层面的问题,用浏览器自带的开发者工具直接调一次接口,或者用一个轻量的HTTP请求工具手动发一次同样的请求,看看能不能复现。如果工具直接请求没问题,那就是脚本构造的请求有问题;如果工具也报错,那就是服务端或网络有问题。这样一刀切下去,问题范围立刻缩半。

第三个经验是“版本管理”。我以前开发压测脚本时走过弯路:改了一堆关联参数,回放出错,又想回滚到上一版,结果没有保存过旧版本,只能重录。后来养成了习惯,每完成一个有意义的改动就导出一次脚本副本并加上版本号备注。这样排查到后面发现是自己某一步改错了,能直接拉旧版本对比,不耽误时间。

7. 一些我固定下来的脚本开发自查顺序

最后分享一个我踩过不少坑后固定下来的自查顺序,思路是先确认环境、再确认脚本逻辑、最后才确认性能结果:

先把网络环境和被测服务的连通性跑一遍,确保脚本要访问的域名、端口、接口都正常,这一步通常花不到十分钟,但能排除大量低级问题。再确认脚本里的参数数据和业务账号是否足够支撑压测规模,尤其是账号、订单号这类数据,宁可多准备也不要在压测中才意识到不够用。接着确认关联字段是否齐全、动态数据是否都被正确处理,这一步可以通过两次连续迭代回放验证。然后才去看事务边界、集合点设计和运行时设置是否符合场景需求。最后用小并发跑一遍场景,观察各指标趋势正常后,再逐渐加大并发量。

做压测这么长时间,我的体会是:VuGen脚本开发看起来是个纯操作性的活,但真正拉开水平差距的,是能不能理解脚本背后的用户行为模型和业务逻辑。脚本是承载业务的,业务没搞懂,脚本写得再规范也没有意义。真正的高手不是说会用多少函数,而是懂得在什么场景下选择什么策略。先在脚本阶段把这个基础夯实,后面Controller里的施压配置、监控分析和瓶颈定位,跑起来会顺很多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询