ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

LoadRunner性能测试实战:从脚本开发到瓶颈定位的完整工程指南

LoadRunner性能测试实战:从脚本开发到瓶颈定位的完整工程指南 1. 从“录制回放”到“性能工程”LoadRunner的定位与价值如果你刚接触性能测试可能觉得LoadRunner就是个“录脚本、跑并发、出报告”的工具。十年前这个认知或许够用但今天如果你还这么想那可能连性能问题的门都摸不着。我干了十多年性能测试从LoadRunner 8.0一路用到最新的SaaS版本最大的体会是LoadRunner早已从一个单纯的“负载模拟器”演变成了一个贯穿性能需求、设计、执行、分析和调优全生命周期的“性能工程平台”。它的核心价值不在于录制了多少个脚本而在于它如何帮你构建一套可量化、可复现、可归因的性能验证体系。很多人一上来就急着问“怎么录制脚本”、“怎么设置并发数”这就像学开车只关心怎么踩油门却不懂交通规则和车辆原理上路必出事故。LoadRunner的“详细使用”第一步必须是理解其背后的工程思想。它解决的远不止“系统能扛多少人”这种粗放问题而是更精细的在特定业务场景下比如双十一秒杀、月末报表生成用户行为模型是怎样的系统的响应时间、吞吐量、资源利用率等关键指标随着负载增加是如何变化的瓶颈在哪里是应用服务器CPU、数据库锁还是网络带宽只有把这些问题想清楚了你的脚本、场景、监控才有意义否则就是一堆没有灵魂的数据。所以这篇教程不会只给你一堆按钮截图和操作步骤。我会带你走一遍一个资深性能测试工程师使用LoadRunner的标准工作流穿插我踩过的坑和总结的技巧目标是让你不仅能“用”起来更能“用好”真正发挥出这个重型武器的威力。无论你是测试新人想系统入门还是有一定经验想提升对性能工程的理解这篇内容都会对你有所帮助。2. 性能测试的基石需求分析与场景建模在打开LoadRunner之前80%的工作已经开始了。性能测试失败十有八九是需求没搞清楚。这一章我们抛开工具先聊聊性能测试的“灵魂”——场景。2.1 从业务指标到性能指标需求拆解实战业务方通常会提“系统要快要能扛住高峰流量。” 这是一个无效需求。作为性能测试工程师你必须把它翻译成可量化的技术指标。我常用的拆解框架是“用户-业务-系统”三层法。用户层指标这是最直观的。比如“登录操作在95%的情况下响应时间不超过2秒”。这里“95%”和“2秒”就是关键。你不能只看平均响应时间一个10秒的请求会拉高99个0.1秒请求的平均值掩盖问题。LoadRunner的报告里90th Percentile、95th Percentile这些百分位数比Average更重要。业务层指标这定义了负载的规模和模式。你需要和产品、运营确认并发用户数是严格的同时操作如秒杀还是时间段内的在线用户如论坛浏览两者天差地别。LoadRunner中对应的概念是“并发用户”和“每秒事务数TPS”。业务模型用户怎么用你的系统比如一个电商用户典型路径可能是20%时间浏览首页30%时间搜索商品40%时间查看商品详情10%时间下单。这个比例就是你的“业务混合模型”它决定了脚本中各个事务的权重。数据量测试用的数据要和生产环境规模匹配。用100条商品数据测出的性能和100万条数据下的性能可能完全不同。你需要准备或模拟相应规模的基础数据。系统层指标这是技术团队最关心的。包括服务器资源CPU使用率通常建议不超过70-80%、内存使用率、磁盘I/O、网络I/O。中间件指标如Tomcat线程池活跃线程数、数据库连接池使用率、JVM GC频率和时长。数据库指标慢查询数量、锁等待时间、缓存命中率。我的经验一定要在测试开始前和所有相关方产品、开发、运维、DBA一起评审并确认这些指标。形成一份《性能测试需求规格说明书》并签字。这能避免后期无尽的扯皮——“你说慢我觉得挺快啊”。2.2. 构建LoadRunner测试场景从理论到配置理解了需求我们才能开始在LoadRunner中构建有意义的场景。在LoadRunner Controller场景控制器中场景设计是核心。虚拟用户组Vuser Groups根据业务模型你会创建多个脚本每个脚本模拟一类用户行为如“浏览用户”、“购买用户”。在场景中你需要为每组虚拟用户设置不同的数量、加载策略和运行时设置。负载生成器Load Generators如果你的并发数很大比如超过1000一台机器可能无法模拟或者会先成为瓶颈。这时就需要在多台机器上部署Load Generator由Controller统一调度。这里有个大坑负载生成器本身会消耗资源。你需要监控负载机的CPU和内存确保其资源充足否则虚拟用户可能无法正常启动或运行导致测试结果失真。我一般会确保负载机的CPU使用率在测试期间低于50%。调度器Schedule这是场景设计的精华部分它定义了负载如何随时间变化。初始化Initialize所有虚拟用户是同时初始化还是分批初始化对于需要登录的脚本我通常选择“同时初始化所有用户”然后在脚本中设置集合点等所有用户初始化完成后再开始真正操作这样能模拟真实的“瞬间并发”压力。启动Start Vusers用户是同时启动还是每隔一段时间启动一批Ramp Up对于系统预热或寻找最大并发点Ramp Up非常有用。例如每15秒启动50个用户直到达到1000用户观察系统指标何时出现拐点。持续时间Duration负载达到峰值后需要持续运行一段时间如30分钟。这能检验系统在持续压力下的稳定性是否有内存泄漏、连接池耗尽等问题。短时冲刺和长时稳压发现的问题类型完全不同。停止Stop Vusers是同时停止所有用户还是逐渐停止通常选择“同时停止”以观察压力释放后系统的恢复情况。一个经典的“波浪形”场景配置可能是5分钟内逐步加载500个虚拟用户 - 保持500用户并发持续运行30分钟 - 在2分钟内全部退出。通过这样的场景你可以分析系统在负载上升期、平稳期和下降期的表现。3. VuGen脚本开发不仅仅是录制LoadRunner的Virtual User Generator (VuGen) 是用来录制和开发脚本的。很多人以为脚本开发就是“点录制操作一遍停止”这是最基础的也是最脆弱的。一个健壮的脚本需要大量的手工增强。3.1 录制与协议选择选错全盘皆输打开VuGen第一步不是点录制而是选择协议。这是第一个关键决策点。LoadRunner支持几十种协议选错了要么录不到任何请求要么录到的请求无法回放。Web (HTTP/HTML)这是最常用的用于测试基于浏览器的Web应用。它录制的是HTTP请求。这里又有HTML-based script和URL-based script的区别。HTML-based默认选项。它将用户操作点击、输入录制为一个个函数如web_link,web_submit_form更贴近用户视角脚本易读性强。适用于大多数前后端耦合、页面跳转频繁的传统Web应用。URL-based它将所有请求包括页面、图片、JS、CSS等录制为独立的web_url函数。脚本看起来是一长串URL请求。适用于前后端分离如单页应用SPA或需要精细控制每个请求的场景。对于现代大量使用Ajax的Web应用我越来越多地使用URL-based模式因为它能更准确地捕捉到异步请求。Web Services用于测试SOAP或RESTful API。这是目前微服务架构下的测试重点。你需要手动导入WSDL文件或直接输入API地址VuGen会生成对应的调用函数。对于API测试参数化和验证点设置更为关键。Java Vuser/C Vuser这是协议无关的直接编写Java或C代码来模拟用户行为。功能最强大也最灵活可以测试任何基于Socket通信的协议或者直接调用JAR包中的方法。但要求测试人员有较高的编程能力。数据库协议如ODBC, Oracle NCA直接测试数据库存储过程或SQL语句的性能。我的踩坑记录曾经测试一个混合了Web页面和Socket长连接的系统只用Web协议录制结果长连接的心跳包完全没录上测试场景完全失真。后来改用多协议Multiple Protocols同时选择Web和Windows Sockets才完整模拟了用户行为。所以对于复杂系统务必分析其通信架构必要时组合使用多种协议。3.2 脚本增强四大核心参数化、关联、检查点、事务录制好的裸脚本几乎无法直接用于压力测试必须增强。3.2.1 参数化Parameterization让虚拟用户“活”起来如果所有虚拟用户都用同一个账号登录、查同一条数据压力会集中到数据库的某一行热点产生大量锁等待这不符合真实情况也测不出系统的真实并发处理能力。目的用不同的数据替换脚本中的常量。比如登录用户名、密码、搜索关键词、商品ID等。操作在VuGen中选中要替换的值右键选择“Replace with a Parameter”。数据文件设计你可以使用.dat文件、数据库作为数据源。我强烈建议为不同的参数创建独立的数据文件并注意数据量要远大于虚拟用户数避免循环使用相同数据。对于“唯一性”要求的数据如注册用户名要选择Unique模式并设置数据耗尽时的行为如Abort Vuser。技巧对于订单号、时间戳这类需要运行时动态生成的数据光参数化不够需要使用lr_save_string,lr_save_datetime等函数在代码中动态生成。3.2.2 关联Correlation处理动态值这是新手最容易栽跟头的地方。服务器返回的很多值是动态的比如Session ID、Token、CSRF令牌、订单流水号。脚本回放时如果还用录制时的旧值请求就会失败。目的自动捕获服务器返回的动态值并保存到参数中供后续请求使用。方法自动关联LoadRunner可以扫描脚本识别可能需要关联的地方。在录制时或回放后使用Scan for Correlation功能。但它不是万能的很多自定义的Token它识别不了。手动关联必须掌握这是核心技能。通过对比录制和回放的服务器返回在Recording Log或Replay Log中查找定位动态值。然后使用web_reg_save_param或web_reg_save_param_ex函数注意是reg注册型函数必须放在请求之前来捕获它。// 例如捕获一个名为csrf_token的隐藏域值 web_reg_save_param_ex( ParamNamecsrf_token, LBinput type\hidden\ name\csrf_token\ value\, RB\, SEARCH_FILTERS, ScopeBody, LAST); // 紧接着才是提交表单的请求 web_submit_form(...); // 后续请求中就可以用{csrf_token}参数了经验关联做得是否彻底是脚本能否成功回放的关键。对于现代应用尤其要关注JSON返回中的Token。你可以写自定义函数来解析JSON并提取值。3.2.3 检查点Checkpoint验证业务是否正确压力测试不只是压测还要验证在高压下业务逻辑是否正确。比如支付成功后页面是否跳转到了成功页搜索是否返回了结果。目的在脚本中设置验证点检查服务器返回的内容中是否包含预期的字符串。函数web_reg_find注册型放在请求前或web_find放在请求后效率低且只对HTML模式有效已逐渐淘汰。最佳实践对关键业务步骤如登录、下单、支付设置检查点。在Controller场景中可以设置“当检查点失败时事务状态为失败”这样在分析报告时你能清晰地看到有多少虚拟用户业务执行失败了而不仅仅是HTTP状态码200。3.2.4 事务Transaction定义你要测量的操作事务是性能指标度量的基本单位。你需要把一系列操作组合成一个逻辑上的业务单元。目的衡量某个业务操作的响应时间如“用户登录”、“添加商品到购物车”、“提交订单”。操作在脚本中插入lr_start_transaction和lr_end_transaction。命名规范事务名要有意义如T01_Login,T02_SearchProduct。避免使用默认的Action。思考时间Think Time用户操作之间的间隔。录制时会包含思考时间。在压力测试时通常需要在运行时设置Run-time Settings中忽略或按比例缩放思考时间以产生更大的压力。但在稳定性测试或模拟真实用户模型时需要保留。3.3 调试与回放确保脚本基石稳固脚本增强后必须在VuGen中单用户迭代运行多次确保回放通过Replay Pass没有错误。日志清晰Log Enabled打开扩展日志Extended Log查看参数替换、关联捕获的值是否正确。数据流正确使用VuGen的集成浏览器或查看Generation Log确认业务流程走通检查点都通过。只有单用户脚本100%稳定才能放到多用户场景中去压测。否则场景中的错误会多到无法分析。4. Controller场景设计与执行监控施加压力的艺术脚本准备好了就进入LoadRunner的“大脑”——Controller。这里是把虚拟用户组织起来向系统发起总攻的地方。4.1 场景类型选择目标场景 vs. 手工场景Controller提供两种主要场景类型手工场景Manual Scenario你直接定义每个脚本的虚拟用户数。这是最常用、最灵活的方式可以精细控制每组用户的数量和调度策略。前面讲的调度器Schedule就是在手工场景中配置。适用于大多数性能验证、容量规划、瓶颈定位测试。目标场景Goal-Oriented Scenario你设定一个测试目标例如每秒完成50个登录事务LoadRunner自动调整虚拟用户数来达到这个目标。这更像是一种“探索性”测试用来回答“要达到某个性能指标需要多少并发用户”这个问题。适用于已知性能指标反推系统容量的场景。我90%的情况使用手工场景因为它能让我完全掌控测试过程。4.2 运行时设置Run-time Settings微调虚拟用户行为在场景中你可以为不同的脚本组设置不同的运行时策略这是一个非常强大的功能。迭代Iteration每个虚拟用户运行脚本的次数。对于长时间稳定性测试可以设置为“无限”直到场景停止。日志Log为了性能考虑在压力测试时通常只启用“出错时发送消息”或完全禁用日志。但在调试阶段可以启用扩展日志。思考时间Think Time如前所述可以忽略、按比例缩放或使用录制的时间。速度模拟Speed Simulation模拟不同的网络带宽如拨号、宽带。这在测试网络敏感型应用时很有用。浏览器模拟Browser Emulation模拟浏览器的缓存和Cookie行为。现代浏览器缓存机制复杂选择合适的模拟级别对结果有影响。4.3 监控器Monitors为系统做“全身CT”压测过程中如果只盯着LoadRunner的虚拟用户状态和事务响应时间那就是“盲人摸象”。你必须实时监控被压测系统的各项资源指标这需要配置监控器。Windows资源监控对于Windows服务器可以直接添加Windows Resources监控器输入服务器IP、管理员账号密码即可监控CPU、内存、磁盘、网络等。UNIX/Linux资源监控需要在目标服务器上安装并启动rstatd或SSH服务然后在Controller中添加UNIX Resources监控器。我更喜欢用SSH方式更安全通用。监控指标包括%usr用户CPU、%sys系统CPU、average load平均负载、disk busy等。SNMP监控对于网络设备路由器、交换机或支持SNMP的服务可以使用SNMP协议监控。应用服务器监控这是重中之重。需要配置特定的监控器。Apache / Nginx需要开启mod_status模块监控请求数、连接数等。Tomcat / JBoss需要开启JMX远程管理监控线程池、内存池、请求队列等。.NET监控.NET CLR内存、异常等。数据库监控Oracle通过OCI接口或配置Oracle Server监控器监控缓冲区命中率、锁等待、Top SQL等。SQL Server通过ODBC或配置SQL Server监控器。MySQL可以使用SiteScopeLoadRunner组件或通过自定义脚本收集SHOW GLOBAL STATUS信息。监控配置的坑监控本身会产生开销。我曾遇到过因为开启了过于频繁的JMX监控每秒一次导致Tomcat在高压下额外消耗了5%的CPU。因此监控粒度要权衡通常5-10秒一次即可。另外防火墙和权限一定要提前开通否则压测开始后监控连不上会非常被动。4.4 执行与现场诊断压测不是“设好就等”点击“Start Scenario”只是开始。在执行过程中你必须像指挥官一样紧盯几个关键面板运行视图Run View查看虚拟用户的状态就绪、运行、完成、错误、每秒事务数、事务响应时间趋势图。如果错误用户数急剧增加或响应时间曲线突然飙升就要立刻警觉。监控器图表观察服务器CPU、内存、磁盘IO、网络IO是否出现瓶颈。数据库活动连接数是否暴增。错误信息Errors实时查看错误日志快速判断是脚本问题如关联失败、网络问题如连接超时还是服务器问题如500内部错误。如果发现问题不要急着停止。可以先尝试分析当前日志从出错的虚拟用户中采样查看其执行日志。调整负载如果怀疑是某个特定功能导致可以尝试在场景运行时动态减少该脚本组的用户数观察系统是否恢复。收集即时数据登录服务器快速执行一些命令如top,vmstat 1,jstack抓取现场信息。压测执行阶段是发现和定位问题最黄金的时期。5. Analysis结果深度解读从数据到洞见压测结束后LoadRunner Analysis会生成一份详细的报告。很多人只看个平均响应时间和通过率就结束了这简直是暴殄天物。Analysis里的数据是诊断系统性能问题的“金矿”。5.1 核心图表解读看懂这些图你就懂了八成运行虚拟用户数图Running Vusers对比你设置的场景计划看虚拟用户是否按计划加载和退出。如果图形有异常凹陷说明有大量用户中途失败退出。每秒事务数图Transactions per Second这是系统吞吐量的直接体现。健康的曲线应该是随着用户数增加而上升在用户数稳定后也保持相对稳定。如果曲线在压力稳定后持续下降说明系统处理能力在衰退可能有资源泄漏。如果曲线出现剧烈锯齿状波动说明系统处理不稳定。事务响应时间图Transaction Response Time一定要结合“运行虚拟用户数图”一起看。响应时间应该随着用户数增加而平缓上升。如果出现拐点即用户数增加一点响应时间急剧上升那个拐点对应的用户数可能就是系统的“最佳并发用户数”。超过这个点系统体验会急剧恶化。点击率图Hits per Second每秒向服务器发出的HTTP请求数。这个图可以和TPS图对照。如果TPS上不去但点击率很高可能意味着前端页面包含了大量无效的静态资源请求或者服务器在处理每个请求时做了很多无用功。系统资源监控图将上述性能指标图与Windows/UNIX资源图叠加Overlay在一起看是定位瓶颈的杀手锏。例如当TPS上不去时如果发现CPU使用率已经达到95%以上那么瓶颈很可能在应用服务器计算能力。如果TPS和CPU都不高但事务响应时间很长同时发现磁盘%busy或await时间很高那么瓶颈可能在磁盘I/O。如果数据库服务器的lock waits或latch waits指标很高那么瓶颈可能在数据库锁竞争。5.2 关键数据表分析细节决定成败除了图表报告中的“事务摘要”、“事务性能摘要”等数据表提供了量化依据。平均响应时间 vs. 百分位数响应时间再次强调不要迷信平均值。关注90th Percentile和95th Percentile。比如平均响应时间1秒但90%线是5秒说明有10%的用户体验极差。通过/失败事务数检查点失败的事务也会被计入失败。分析失败事务的原因是脚本问题还是服务器错误。标准差Std. Deviation响应时间的标准差越大说明系统性能越不稳定。5.3 瓶颈定位与调优建议输出有价值的报告一份好的性能测试报告不应该只是数据的罗列而应该包含测试结论在给定的场景和指标下系统是否通过测试性能表现核心事务的响应时间、TPS、资源利用率等关键数据。瓶颈分析结合图表和数据明确指出发现的性能瓶颈在哪里并尽可能分析根因。例如“在500并发用户下‘提交订单’事务的响应时间超过5秒不符合≤3秒的要求。同时观察到数据库服务器CPU使用率达92%且存在大量‘CPU wait’状态推测是某条SQL语句未使用索引导致的全表扫描。”调优建议给出具体的、可操作的改进建议。例如“建议对orders表的user_id字段添加索引并优化GetUserOrders存储过程的逻辑避免在循环内执行查询。”风险与后续计划指出未覆盖的场景、测试的局限性以及是否需要补充测试如疲劳测试、异常测试。6. 高级话题与实战避坑指南掌握了基础流程我们再来聊聊那些让新手头疼、老手翻车的高级问题和实战技巧。6.1 脚本开发中的“硬骨头”动态令牌、异步请求与SSL证书动态令牌如JWT现代API常用JWT。处理方法是在登录事务后使用web_reg_save_param_ex捕获返回的Token通常在响应头的Authorization字段或JSON Body中。然后在后续请求的Header中使用web_add_header函数添加Authorization: Bearer {token}。异步请求Ajax对于URL-based脚本Ajax请求会被录制成独立的web_url顺序可能和实际有差异。你需要分析请求间的依赖关系必要时使用web_concurrent_start和web_concurrent_end函数来模拟并发请求或者手动添加等待lr_think_time以确保数据就绪。SSL证书问题在录制或回放HTTPS网站时可能会遇到证书错误。可以在VuGen的Recording Options-Network-Port Mapping中将捕获级别设置为WinINet用于IE浏览器或Socket并勾选“Capture level”下的相关SSL选项。对于自签名证书需要将证书导入到系统的信任库。6.2 场景执行中的典型问题与排查虚拟用户无法初始化/启动失败错误提示“Failed to create Vuser”检查License是否支持这么多用户负载生成器机器资源内存是否充足。错误提示“Failed to connect to load generator”检查负载生成器上的Agent Process是否启动Controller与负载机之间的防火墙端口默认50500、54345是否开放。大量错误“Action.c(x): Error -27796: Failed to connect to server”这是连接超时。首先检查被压测服务器网络是否可达端口是否监听。更常见的原因是压力过大服务器端的连接池如Web服务器、数据库被耗尽新的连接无法建立。此时需要监控服务器端的活动连接数。在运行时设置中适当增加HTTP-request connect timeout和HTTP-request receive timeout可能缓解但根本解决需要调整服务器配置。事务响应时间逐渐变长TPS逐渐下降这是典型的内存泄漏或资源未释放症状。检查应用服务器的内存使用曲线是否持续上升。检查数据库连接是否在执行后正确关闭。进行长时间如8-24小时的稳定性测试耐力测试最容易暴露这类问题。6.3 结果分析中的常见误区只看汇总报告不看细分事务系统整体平均响应时间达标但某个核心事务如支付可能很慢。必须逐个分析关键事务。忽略基础资源监控有时TPS和响应时间看起来正常但磁盘队列长度已经很高这是潜在瓶颈一旦数据量增大就会爆发。将一次测试结果当作最终结论性能测试结果受环境数据、网络、其他进程、参数思考时间、迭代次数影响很大。关键结论需要多次测试验证特别是调优前后必须保证测试环境、场景、数据的一致性才能进行有效对比。LoadRunner是一个强大的工具但工具背后的性能工程思维和严谨的方法论更为重要。它要求你既是懂业务的测试者也是能看透系统架构的侦探。从精准的需求分析开始到健壮的脚本开发再到科学的场景设计和严谨的结果分析每一步都环环相扣。真正的“详细使用”是把这个工具融入到你保障系统性能质量的完整工作流中让每一次压测都有的放矢让每一份报告都言之有物。这个过程没有捷径唯有多实践、多思考、多总结。当你能够通过LoadRunner的数据清晰地描绘出系统在压力下的行为图谱并精准地指出它的“阿喀琉斯之踵”时你才算真正掌握了它。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进