资讯详情

性能测试参数化必知:参数值读取设置与并发场景配置详解

📅 2026/10/16 4:12:20 | 华诺云谱 👁 阅读
性能测试参数化必知:参数值读取设置与并发场景配置详解
搞性能测试这些年参数化是脚本开发里被问得最多的一块。很多人都会做参数把写死的用户名、密码、订单号替换成参数但做到后面常常翻车并发用户数一上去数据错乱、重复登录、业务失败翻日志一看全是参数值设置的问题。这个锅很多时候不是参数文件本身而是“参数值读取设置”没配对。LoadRunner里叫“参数值读取设置”的核心其实就是两个下拉框Select next row选择下一行和Update value on值更新时机再加上Controller里的数据分配策略。这三个东西单独看每个都懂但组合起来能玩出十几种行为差异选错一个就是整场压测结果失真。这篇文章我就按实际排障时积累的思路把这个参数值读取设置讲透包括每个选项背后的行为逻辑、不同组合适合什么业务场景、以及我在真实项目中踩过的一些坑。1. 参数值读取设置到底在解决什么问题1.1 参数化不只是替换硬编码很多人把参数化理解成“把脚本里的固定值换成变量”这个理解没错但只对了一半。真正的价值在于压测时要模拟大量真实用户而真实用户之间的数据一定是不同的。如果脚本里用户名写死成同一个那所有虚拟用户都用同一个账号去登录、下单、查询服务端看到的请求就是极度失真的命中缓存、互踢下线、风控拦截这些问题会全部混进测试结果里。所以参数化的本质是给虚拟用户提供一个“数据池”每个用户按一定规则从池子里取数据。而这个取数规则就是参数值读取设置要管的事情。我在实际项目中会把读取设置拆成三个问题一个虚拟用户从哪个位置开始取数据它什么时候切换到下一条数据多个虚拟用户之间如何避免互相踩数据。Select next row、Update value on、Controller里的分配策略这三点正好一一对应。搞懂这三个问题参数化就算真正入门了。1.2 选错读取设置会翻什么车直接说几个我见过的真实事故你会更直观。第一个注册场景所有虚拟用户都在用同一个手机号注册。不管并发多少注册失败率都接近100%日志里清一色“手机号已存在”。这不是被测系统有问题是参数没做对。第二个登录场景数据池里有50组账号50个虚拟用户压登录接口。很多人以为数据池有50组账号并发50就是一人一组结果跑起来发现所有虚拟用户第一次迭代全都在用第一组账号登录直接把那个账号顶下线后面大量401。这个坑在于没搞清楚选择下一行里Sequential和Unique的区别。第三个查询场景一个虚拟用户跑100次迭代每次都查同一个订单号结果服务端把热点数据缓存命中得飞起TPS高得离谱。表面看参数化了实际上和没参数化没有任何区别。这些问题的共同点就是参数值读取设置和真实的业务数据模型不匹配。所以说参数化不是一个机械操作它是在用数据模型模拟生产流量。2. 两个核心开关Select next row 和 Update value on2.1 Select next row数据序列的推进规则这个下拉框有三个选项Sequential顺序、Random随机、Unique唯一。Sequential字面意思是顺序取数每个虚拟用户启动时都会建立自己的游标然后从数据池第一行开始按行号递增取数。注意这里的“自己游标”很关键也就是说N个虚拟用户各自独立地从第一行开始相同迭代次数取到的是同一行。这一点和直觉不一样很多人默认以为Sequential会让不同用户自动错开实际不会。Random就是每次取数时随机定位一行。它的好处是分布均匀坏处是会发生重复。如果业务上允许重复、只需要数据有变化Random很合适。但注意如果两个参数分别用Random那两次随机取出来的行可能对不上。Unique是全局唯一模式。LoadRunner会维护一个全局计数器确保整个场景过程中取到的值不重复。它最适合用户名、手机号、身份证这类必须唯一的业务字段。但代价是数据池必须有足够多的行否则直接在日志里给你报“Not enough values for the Unique parameter”。除了这三个选项同一个参数如果对应文件里的多列下面还有一个不起眼的“Same line as”下拉框。它的作用是当前参数取第N行的同时让另一个参数也取第N行。比如userName和userPass在同一个文件里如果userName选了RandomuserPass不设置Same line as就会随机取到一个不一定匹配的密码账号密码对不上。这个细节我在后面实操里会重点讲。2.2 Update value on值到底什么时候更新这个下拉框有三个选项Each occurrence每次出现、Each iteration每次迭代、Once一次。Each occurrence的意思是脚本运行过程中只要碰到一次对这个参数的引用就去取一个新值。如果一次迭代里同一个参数被引用了三次那这一个迭代就要消耗掉三行数据。Each iteration的意思是同一个迭代里无论这个参数被引用多少次都只取同一个值等到下一次迭代开始再取下一个值。这是最常用的方式既保证了数据有变化又避免单次迭代内数据错乱。Once的意思是虚拟用户在整个生命周期里只取一个值后续哪怕跑几十次迭代都用这个值。这个选项适合那种需要模拟“一个用户持续操作”的场景比如一个虚拟用户对应一个真实用户登录之后反复做查询、下单等操作数据不该中途变化。这里隐藏了一个特别容易被忽视的变量脚本里同一个参数的“引用次数”。如果你不确定一次迭代里它被引用了几次后面的取值行为就完全不可控。2.3 引用次数才是隐藏变量看个简单例子脚本里有两个请求都用到了{login_user}web_submit_data(login, Actionhttp://xxx/api/login, ... Nameusername, Value{login_user}, ENDITEM, ...); web_url(profile, Urlhttp://xxx/user/{login_user}/profile, ...);这个脚本在一次迭代里{login_user}被引用了两次。如果Update value on选择Each occurrence那么login请求取的是第一行数据profile请求会自动取第二行数据一个用户还没操作完数据已经跳走了业务逻辑直接断裂。如果选择Each iteration那么这两个请求拿到的是同一个值逻辑才是连贯的。所以每次配置参数之前先数一遍脚本中这个参数的引用次数再决定Update value on选什么。我见过很多人图省事直接选Each occurrence结果数据消耗快不说单次迭代内前后不一致排查起来非常痛苦。3. 组合矩阵和场景对照3.1 8种组合行为对照Select next row和Update value on一共能组合出8种行为。落到实际项目里常用的其实也就四五种。我整理了一张表方便你对照着选Select next rowUpdate value on实际行为典型场景SequentialOnce每个虚拟用户固定取第一行之后所有迭代都用它基本不用除非你刻意让所有用户用一个数据SequentialEach iteration每个虚拟用户从第一行开始每次迭代取下一行数据可重复、不要求用户间隔离的压测SequentialEach occurrence每一次引用都顺序取下一行很少用于业务逻辑容易导致单次迭代内前后不统一RandomEach iteration每次迭代随机取一行校验码、随机查询参数等可重复数据RandomEach occurrence每次引用随机取一行不关注对应关系的纯随机数据UniqueOnce每个虚拟用户分配一个全局唯一值整个场景不变一个Vuser模拟一个真实用户持续操作UniqueEach iteration每次迭代取一个全局唯一值各用户互不重复登录、注册、下单等高频并发业务首选UniqueEach occurrence每次引用都消耗一个全局唯一值数据量极度充裕时才用消耗速度极快这张表看着简单但每次选完你都应该能回答自己一句我为什么这么组合。如果答不上来大概率是蒙的后面必踩坑。3.2 从业务需求倒推配置而不是从选项硬选既然组合这么多正确的选法是从业务模型倒推。先问自己四个问题这个字段允许不同用户重复吗同一个虚拟用户的不同迭代之间数据该变还是该不变一次迭代里如果多次引用这个字段是不是必须保持一致数据池里到底准备了多少行数据够不够Unique模式消耗这四个问题的答案基本直接指向某个组合。举个例子登录接口的账号密码每个账号只允许一个用户在线那必须选Unique不然并发用户会互踢。如果业务上允许同一账号多点登录那SequentialEach iteration就够了数据消耗也小。再举个例子查询接口的订单号同一个用户每次迭代应该换一个订单号去查否则会形成热点访问。这种情况UniqueEach iteration很合适数据池行数够的话完全按真实用户行为来。如果是压测一个纯随机验证码生成接口数据重复完全没影响那直接用RandomEach iteration省数据也不会有副作用。记住一个原则没有绝对最好的组合只有和业务模型最匹配的组合。参数值读取设置本身就是把业务规则翻译成LoadRunner的取值逻辑。4. 实操登录脚本参数化的完整配置过程4.1 先把脚本里的硬编码替换成参数我以最常用的登录场景为例子完整走一遍。在VuGen里录制完登录操作后脚本里会有一个写死的用户名比如web_submit_data(login, Actionhttp://xxx/api/login, ... Nameusername, Valuetestuser100, ...在VuGen脚本编辑器里选中这串写死的用户名右键选择“Replace with a parameter”弹窗里填参数名login_user。这样脚本里就变成了{login_user}。这只是参数化的第一步。此时参数值怎么取、什么时候更新都还没有定义需要打开参数列表继续配置。4.2 参数文件和多列对齐在参数列表中新建参数时类型先选File这是最常用的文件数据源类型。文件内容我用记事本维护格式很简单userId,userName,userPass 1,user01,pass01 2,user02,pass02 3,user03,pass03第一行是列名后面每一行是一条数据。列与列之间用英文逗号分隔LoadRunner默认读取时File参数会按列名去定位。登录接口需要提交用户名和密码所以这里应该建两个参数login_user和login_pass。它们指向同一个文件login_user对应userName列login_pass对应userPass列。在login_pass的参数配置里有一个“Same line as”选项把它设置成login_user这样两个参数每次取的都是同一行账号和密码才能对得上。这里有个坑经常有人踩如果两个参数分别设置了Random然后没设置Same line as就会出现账号密码错配登录永远失败。你排查半天脚本、网络、服务端最后发现是参数取数错位非常无语。再提醒一个细节文件编码。用Windows记事本保存utf-8格式时会在文件头写入BOMLoadRunner读取时可能会把第一列第一行的字段名带上一个不可见字符导致这个字段匹配不上。我在项目里遇到过好几次最后的解决办法是改用无BOM的UTF-8编码保存或者直接用ANSI编码。文件内容里不要有中文时用ANSI问题不大有中文时建议用无BOM的UTF-8。4.3 调试验证确认取到的值符合预期配置完成后先别急着上并发。在VuGen里做两件事确认参数取值是否正确。第一件事打开Run-Time Settings找到General Log把Extended log里的“Parameter substitution”勾上。这个选项会把每次参数替换后的实际值全部打印到日志里是排查参数问题最直接的工具。第二件事在脚本里加一行输出把当前取到的值打出来lr_message(当前登录用户: %s, lr_eval_string({login_user})); lr_message(当前登录密码: %s, lr_eval_string({login_pass}));然后用迭代模式跑三到五次看日志里打印出来的用户和密码是否按预期变化、是否始终配对。确认没问题之后再把这个扩展日志关掉。开着Parameter substitution跑大并发会严重影响脚本执行效率生产级测试里一般不长时间开。5. 高并发场景下的数据分配策略别只盯着VuGen5.1 VuGen调试和Controller运行的差异很多人在VuGen里调脚本时一切正常一旦放到Controller里跑场景就发现参数值全部重复、数据错乱。这个现象基本可以断定忽略了Controller里的数据分配策略。VuGen调试时只有一个虚拟用户不管Unique还是Sequential它都是从数据池第一个值开始取所以怎么看怎么对。但Controller里跑的是几十上百个虚拟用户LoadRunner还要处理一个关键问题这么多用户同时启动怎么给它们分数据才不会互相抢占。默认情况下如果不做任何设置Unique模式下不同虚拟用户有可能从同一个起始位置开始取数据结果就是整个场景里大家都在抢同一段数据。解决方式是在场景的Parameter Properties里启用“Allocate Vuser values in the Controller”让Controller在场景开始时给每个虚拟用户分配一个独立的数据区间。5.2 数据量估算公式和Block设置Controller里启用分配后会要求设置一个“Block size”。这个值的意思是每个虚拟用户一次性预分配多少行参数值。我的经验是Block size直接设置成等于或略大于每个虚拟用户的最大迭代次数。举个例子50个虚拟用户每个用户迭代30次登录脚本每次迭代只引用一次login_user。数据池至少需要50乘以30等于1500条数据Block size设置为30这样的话虚拟用户1使用第1到30条虚拟用户2使用第31到60条以此类推互不重叠。如果数据池只有500条硬要跑1500次消耗Unique模式肯定会报数据不足。这时候有几个变通思路换Random模式允许重复数据不足问题不存在但业务上要确认重复可接受减少迭代次数或虚拟用户数在Unique模式下勾选“Continue in a cyclic manner”。注意勾了循环之后实际上已经破坏了全局唯一性只是从报错变成了循环复用适合一些对数据唯一性要求不高的场景。数据量计算公式随手记一下所需数据量 ≈ 虚拟用户数 × 每用户迭代次数 × 单次迭代内参数引用次数其中“单次迭代内参数引用次数”只有在你选择Each occurrence时才需要乘进去选Each iteration时这个数等于1。5.3 多参数分配时的联动问题数据分配策略里还有一个容易踩的联动问题login_user和login_pass两个参数Controller分配时是分别分配、互不感知的。你必须在参数文件层面保证它们取的是同一行的记录。我的习惯做法是把账号和密码合成一个参数比如file参数只建一个login_data参数文件里每行写成“user01:pass01”然后脚本里用字符串函数把这个参数拆成两个变量。这样取数时天然就是同一行不存在错配的可能。如果你还是倾向于用两个独立参数那就一定要把“Same line as”配置好并且在Controller里检查两个参数的Block size设置保持一致否则一个参数分到前30行另一个参数分到后30行照样错位。这个多参数对齐的问题在真实项目中非常常见。特别是参数化订单号和订单金额的时候订单号和金额必须永远保持同一行不然压出来的数据全是逻辑错误的脏数据。6. 常见问题与排查技巧实录6.1 高频问题速查表把这些年遇到过的参数读取设置相关问题整理成一张表排查的时候照着查就行现象可能原因排查方向所有用户登录用的都是同一账号Select next row用了Sequential不同Vuser游标都从第1行开始换Unique并在Controller里启用分配策略日志报Not enough values for the Unique parameter数据池行数小于总消耗量按公式算数据量扩数据或调Block size同一个迭代内两次请求数据不一致Update value on选了Each occurrence改成Each iteration账号和密码错配导致登录失败两个参数随机取值且没设Same line as设置Same line as或合并成一个参数参数文件里的字段读不出来编码BOM问题或列名不匹配换无BOM编码检查列名Controller跑场景时数据才出错VuGen正常没启用Allocate Vuser values in the Controller在场景参数属性里启用分配数据量明明够但日志里大量重复Controller里没设置Block size多个Vuser抢占前几行设置Block size按用户维度隔离数据6.2 一次并发登录被踢下线的完整排查过程拿一次实际排障来还原过程。模拟项目X里50个虚拟用户压测登录接口场景运行后大量事务失败日志里能看到部分请求返回401和会话失效。刚开始怀疑是被测系统的会话管理问题或者是并发数太高触发了安全策略。后来把扩展日志打开勾选Parameter substitution重新跑小并发发现一个规律大量虚拟用户第一次迭代取到的是同一组账号。再一看脚本里login_user的配置Select next row是SequentialUpdate value on是Each iteration数据池里虽然有50组账号但因为每个虚拟用户的游标都从第1行开始所以第1次迭代所有用户都取第1组账号50个人同时用同一账号登录服务端自然会踢掉前一个会话。定位之后修复就很简单把Select next row改成UniqueUpdate value on保持Each iteration然后在Controller的Parameter Properties里启用Allocate Vuser valuesBlock size设为每个用户的最大迭代次数。重跑之后50个虚拟用户每组账号全程独立登录成功率恢复正常。这个案例里脚本本身没有语法错误参数文件也没问题纯粹是读取设置和业务模型不匹配。所以建议你每次压测前都养成一个习惯先问一遍自己的参数配置到底在模拟什么业务行为。6.3 从日志中快速抓取参数值排查参数问题时除了扩展日志里的Parameter substitution我还会在脚本里手动打日志特别是在循环里输出关键参数for (i 0; i 10; i) { lr_message(第%d次迭代取到用户%s, i, lr_eval_string({login_user})); // 业务请求... }这种方式能定位到具体某一次迭代的参数值比翻庞大的replay log高效很多。调试完记得把这条日志删掉或注释掉不然大并发时会刷爆日志文件。还有一个小技巧修改参数文件后不需要重录脚本LoadRunner会在每次场景启动时重新读取文件。但有的时候如果测试过程中临时改了文件内容正在运行的场景不会即时加载必须重启场景才能生效。别在场景运行中指望动态刷新参数文件这个设计本来就不是为热更新准备的。另一个经验是参数文件里的数据一定要随机化。很多人图省事把测试数据按顺序排好比如user001、user002这样递增。压测时如果业务方对数据分布敏感顺序化数据会让服务端某些基于ID范围的逻辑被频繁命中导致测试结果失真。建议在准备数据时就用程序随机打乱让数据池尽量接近生产分布。最后再分享一个小技巧每次配置完参数值读取设置我习惯先构造一个小数据集5到10行在VuGen里跑两次小迭代再Controller里起两三个Vuser跑一遍用扩展日志核对用户取值分布。确认无误之后再换成完整数据集、正式并发数。这套笨办法帮我避免了很多“场景跑到一半才发现数据池不够”的尴尬。参数值读取设置这个东西看着只是两个下拉框但每一个组合都直接影响压测结果的可信度值得花十几分钟想清楚再动手。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑