16. 最佳实践¶
16.1 始终使用最新版本的 JMeter ¶
JMeter 的性能不断提高,因此强烈建议用户使用最新版本。
确保您始终阅读更改列表以了解新的改进和组件。您绝对应该避免使用比最后一个版本早 3 个版本的版本。
16.2 使用正确的线程数¶
您的硬件功能以及测试计划设计都会影响您可以使用 JMeter 有效运行的线程数。该数字还取决于您的服务器有多快(更快的服务器会使 JMeter 工作得更努力,因为它会更快地返回响应)。与任何负载测试工具一样,如果您没有正确调整线程数量,您将面临“协调遗漏”问题,这可能会给您带来错误或不准确的结果。如果您需要大规模负载测试,请考虑使用(或不使用)分布式模式在多台机器上运行多个 CLI JMeter 实例。当使用分布式模式时,结果文件在Controller节点上合并,如果使用多个自治实例,可以合并样本结果文件进行后续分析。为了测试 JMeter 在给定平台上的表现,可以使用 JavaTest 采样器。它不需要任何网络访问,因此可以提供一些关于可实现的最大吞吐量的想法。
JMeter 可以选择延迟线程创建直到线程开始采样,即在任何线程组延迟和线程本身的加速时间之后。这允许线程总数非常大,前提是没有太多同时处于活动状态。
16.4 授权管理器的放置位置¶
有关信息,请参阅构建高级 Web 测试。
16.5 使用 HTTP(S) 测试脚本记录器¶
有关设置记录器的详细信息,请参阅HTTP(S) 测试脚本记录器。最重要的事情是过滤掉所有你不感兴趣的请求。例如,记录图像请求是没有意义的(可以指示 JMeter 下载页面上的所有图像 - 请参阅HTTP 请求)。这些只会使您的测试计划变得混乱。最有可能的是,所有文件共享都有一个扩展名,例如.jsp、.asp、.php、.html等。您应该通过输入“ .*\.jsp ”作为“包含模式”来“包含”这些内容。
或者,您可以通过输入“ .*\.gif ”作为“排除模式”来排除图像。根据您的应用程序,这可能是也可能不是更好的方法。您可能还必须排除样式表、javascript 文件和其他包含的文件。测试您的设置以验证您正在录制您想要的内容,然后擦除并重新开始。
HTTP(S) 测试脚本记录器希望找到一个 ThreadGroup 元素,它下面有一个记录控制器,它将记录 HTTP 请求。这可以方便地将您的所有样本打包在一个控制器下,该控制器可以指定一个描述测试用例的名称。
现在,完成测试用例的步骤。如果您没有预定义的测试用例,请使用 JMeter 记录您的操作以定义您的测试用例。完成一系列明确的步骤后,将整个测试用例保存在适当命名的文件中。然后,擦干净并开始一个新的测试用例。通过这样做,您可以快速记录大量的测试用例“草稿”。
HTTP(S) 测试脚本记录器最有用的功能之一是您可以从记录的样本中抽象出某些常见元素。通过 在测试计划级别或 用户定义的变量元素中定义一些用户定义的变量,您可以让 JMeter 自动替换您记录的样本中的值。例如,如果您正在服务器“ xxx.example.com ”上测试一个应用程序,那么您可以定义一个名为“ server ”的变量,其值为“ xxx.example.com ”,并且在您记录的任何地方都可以找到该值样本将替换为“ ${server} ”。
如果 JMeter 没有记录任何样本,请检查浏览器是否真的在使用代理。如果即使 JMeter 没有运行,浏览器也可以正常工作,则浏览器不能使用代理。一些浏览器会忽略localhost或127.0.0.1的代理设置;尝试改用本地主机名或 IP。
错误“ unknown_ca ”可能表示您正在尝试记录 HTTPS,并且浏览器尚未接受 JMeter 代理服务器证书。
16.6 用户变量¶
一些测试计划需要为不同的用户/线程使用不同的值。例如,您可能想要测试一个需要每个用户唯一登录的序列。这很容易通过 JMeter 提供的工具来实现。
例如:
- 创建一个包含用户名和密码的文本文件,用逗号分隔。将其放在与您的测试计划相同的目录中。
- 将 CSV 数据集配置元素添加到测试计划。将变量命名为USER和PASS。
- 在适当的采样器上 用${USER} 替换登录名,用${PASS}替换密码
CSV 数据集元素将为每个线程读取一个新行。
16.7 减少资源需求¶
关于减少资源使用的一些建议。
- 使用CLI模式:jmeter -n -t test.jmx -l test.jtl
- 使用尽可能少的 Listeners;如果使用上面的-l标志,它们都可以被删除或禁用。
- 不要在负载测试期间使用“查看结果树”或“在表中查看结果”侦听器,仅在脚本编写阶段使用它们来调试脚本。
- 与其使用大量相似的采样器,不如在循环中使用相同的采样器,并使用变量(CSV 数据集)来改变样本。[包含控制器在这里没有帮助,因为它将文件中的所有测试元素添加到测试计划中。]
- 不要使用功能模式
- 使用 CSV 输出而不是 XML
- 只保存您需要的数据
- 使用尽可能少的断言
- 使用性能最高的脚本语言(参见 JSR223 部分)
如果您的测试需要大量数据 - 特别是如果需要随机化 - 在可以使用 CSV 数据集读取的文件中创建测试数据。这避免了在运行时浪费资源。
16.8 BeanShell 服务器¶
BeanShell 解释器有一个非常有用的特性——它可以充当服务器,可以通过 telnet 或 http 访问。
如果您确实希望使用服务器,请在jmeter.properties中定义以下内容:
beanshell.server.port=9000 beanshell.server.file=../extras/startup.bsh
在上面的示例中,服务器将被启动,并将侦听端口9000和9001。端口9000将用于 http 访问。端口9001将用于 telnet 访问。startup.bsh文件将由服务器处理,可用于定义各种函数和设置变量。启动文件定义了设置和打印 JMeter 和系统属性的方法。这是您应该在 JMeter 控制台中看到的内容:
Startup script running Startup script completed Httpd started on port: 9000 Session started on port: 9001
有一个示例脚本 ( extras/remote.bsh ) 可用于测试服务器。[查看它以了解它是如何工作的。]
在 JMeter bin目录中启动它时(如果从其他地方运行,则根据需要调整路径),输出应如下所示:
$ java -jar ../lib/bshclient.jar localhost 9000 ../extras/remote.bsh Connecting to BSH server on localhost:9000 Reading responses from server … BeanShell 2.0b5 - by Pat Niemeyer (pat@pat.net) bsh % remote.bsh starting user.home = C:\Documents and Settings\User user.dir = D:\eclipseworkspaces\main\JMeter_trunk\bin Setting property 'EXAMPLE' to '0'. Setting property 'EXAMPLE' to '1'. Setting property 'EXAMPLE' to '2'. Setting property 'EXAMPLE' to '3'. Setting property 'EXAMPLE' to '4'. Setting property 'EXAMPLE' to '5'. Setting property 'EXAMPLE' to '6'. Setting property 'EXAMPLE' to '7'. Setting property 'EXAMPLE' to '8'. Setting property 'EXAMPLE' to '9'. EXAMPLE = 9 remote.bsh ended bsh % … disconnected from server.
作为一个实际示例,假设您有一个在 CLI 模式下运行的长时间运行的 JMeter 测试,并且您希望在测试期间的不同时间改变吞吐量。测试计划包括一个恒定吞吐量计时器,它是根据属性定义的,例如${__P(throughput)}。以下 BeanShell 命令可用于更改测试:
printprop("throughput"); curr = Integer.decode(args[0]); // Start value inc = Integer.decode(args[1]); // Increment end = Integer.decode(args[2]); // Final value secs = Integer.decode(args[3]); // Wait between changes while(curr <= end) { setprop("throughput",curr.toString()); // Needs to be a string here Thread.sleep(secs*1000); curr += inc; } printprop("throughput");
该脚本可以存储在一个文件中(例如, throughput.bsh),并使用bshclient.jar发送到服务器。例如:
java -jar ../lib/bshclient.jar localhost 9000 throughput.bsh 70 5 100 60
16.9 BeanShell 脚本¶
16.9.1 概述¶
每个 BeanShell 测试元素都有自己的解释器副本(对于每个线程)。如果测试元素被重复调用,例如在循环中,则解释器在调用之间保留,除非选择了“ Reset bsh.Interpreter before each call ”选项。
一些长时间运行的测试可能会导致解释器使用大量内存;如果是这种情况,请尝试使用重置选项。
您可以使用命令行解释器在 JMeter 之外测试 BeanShell 脚本:
$ java -cp bsh-xxx.jar[;other jars as needed] bsh.Interpreter file.bsh [parameters]或者
$ java -cp bsh-xxx.jar bsh.Interpreter bsh% source("file.bsh"); bsh% exit(); // or use EOF key (e.g. ^Z or ^D)
16.9.2 共享变量¶
变量可以在启动(初始化)脚本中定义。除非使用重置选项,否则这些将在测试元素的调用中保留。
脚本还可以使用“ vars ”变量的get()和put()方法访问 JMeter 变量,例如:
vars.get("HOST"); vars.put("MSG","Successful");get()和put()方法仅支持具有 String 值 的变量,但也有getObject()和putObject()方法可用于任意对象。JMeter 变量是线程本地的,但可以被所有测试元素(不仅仅是 Beanshell)使用。
如果您需要在线程之间共享变量,则可以使用 JMeter 属性:
import org.apache.jmeter.util.JMeterUtils; String value = JMeterUtils.getPropDefault("name",""); JMeterUtils.setProperty("name", "value");示例.bshrc文件包含getprop()和setprop()方法的示例定义。
共享变量的另一种可能方法是使用“ bsh.shared ”共享命名空间。例如:
if (bsh.shared.myObj == void){ // not yet defined, so create it: myObj = new AnyObject(); } bsh.shared.myObj.process();与其在 test 元素中创建对象,不如在 JMeter 属性“ beanshell.init.file ”定义的启动文件中创建它。这只处理一次。
16.10 Groovy 或 Jexl3 等开发脚本函数¶
将脚本作为函数编写和测试非常困难。但是,JMeter 有 JSR223 采样器,它可以与任何支持它的语言一起使用。我们建议使用Apache Groovy或任何支持 JSR223 的Compilable接口的语言。
创建一个包含 JSR223 采样器和树视图侦听器的简单测试计划。在采样器脚本窗格中对脚本进行编码,并通过运行测试对其进行测试。如果有任何错误,这些将显示在树视图和jmeter.log文件中。运行脚本的结果也将显示为响应。
一旦脚本正常工作,它就可以作为变量存储在测试计划中。然后可以使用脚本变量来创建函数调用。例如,假设 Groovy 脚本存储在变量RANDOM_NAME中。然后可以将函数调用编码为${__groovy(${RANDOM_NAME})}。脚本中不需要转义任何逗号,因为函数调用在变量的值被插值之前被解析。
16.11 参数化测试¶
通常,能够使用不同的设置重新运行相同的测试很有用。例如,更改线程数或循环数,或更改主机名。
一种方法是在测试计划中定义一组变量,然后在测试元素中使用这些变量。例如,可以定义变量LOOPS=10,并在线程组中将其称为${LOOPS}。要使用 20 个循环运行测试,只需更改测试计划中LOOPS变量的值。
如果您想在 CLI 模式下运行大量测试,这很快就会变得乏味。对此的一种解决方案是根据属性定义测试计划变量,例如LOOPS=${__P(loops,10)}。这使用属性“ loops ”的值,如果未找到该属性,则默认为10 。然后可以在 JMeter 命令行上定义 “ loops ”属性:
jmeter … -Jloops=12 …如果有很多属性需要一起更改,那么实现此目的的一种方法是使用一组属性文件。可以使用-q命令行选项 将适当的属性文件传递给 JMeter 。
16.12 JSR223 元素¶
对于密集负载测试,推荐的脚本语言是 ScriptingEngine 实现Compilable接口的脚本语言。Groovy 脚本引擎实现了 Compilable。但是,截至 JMeter 3.1 的发布日期,Beanshell 和 Javascript 都没有这样做,因此建议避免使用它们进行密集的负载测试。
vars.get("varName")
您还可以将它们作为参数传递给脚本并以这种方式使用它们。
16.13 在线程和线程组之间共享变量¶
变量是线程本地的;在一个线程中设置的变量不能在另一个线程中读取。这是设计使然。对于可以在测试开始之前确定的变量,请参阅 参数化测试(上文)。如果在测试开始之前该值未知,则有多种选择:
- 将变量存储为属性 - 属性对于 JMeter 实例是全局的
- 将变量写入文件并重新读取它们。
- 使用bsh.shared命名空间 - 见上文
- 编写自己的 Java 类
16.14 管理属性¶
当您需要修改 jmeter 属性时,请确保不要修改jmeter.properties文件,
而是从jmeter.properties复制属性并在user.properties文件中修改其值。
这样做将使您轻松迁移到 JMeter 的下一个版本。
请注意,在文档中经常提到jmeter.properties,但这应该理解为“将要修改的属性从jmeter.properties复制到user.properties并在后一个文件中进行”。