跳到主要内容

最佳实践

16.1 始终使用最新版本的 JMeter

JMeter 的性能不断提高,因此强烈建议用户使用最新版本。
确保你始终阅读 更改列表 以了解新的改进和组件。你绝对应该避免使用比最后一个版本早 3 个版本的版本。

16.2 使用正确的线程数

你的硬件功能以及测试计划设计都会影响你可以使用 JMeter 有效运行的线程数。该数字还取决于你的服务器有多快(更快的服务器会使 JMeter 工作得更努力,因为它会更快地返回响应)。与任何负载测试工具一样,如果你没有正确调整线程数量,你将面临协调遗漏问题,这可能会给你带来错误或不准确的结果。如果你需要大规模负载测试,请考虑使用(或不使用)分布式模式在多台机器上运行多个 CLI JMeter 实例。当使用分布式模式时,结果文件在 Controller 节点上合并,如果使用多个自治实例,可以合并样本结果文件进行后续分析。为了测试 JMeter 在给定平台上的表现,可以使用 JavaTest 采样器。它不需要任何网络访问,因此可以提供一些关于可实现的最大吞吐量的想法。

JMeter 可以选择延迟线程创建直到线程开始采样,即在任何线程组延迟和线程本身的加速时间之后。这允许线程总数非常大,前提是没有太多同时处于活动状态。

16.3 Cookie 管理器的放置

有关信息,请参阅构建 Web 测试

16.4 授权管理器的放置

有关信息,请参阅构建高级 Web 测试

16.5 使用 HTTP(S) 测试脚本记录器

有关设置记录器的详细信息,请参阅 HTTP(S) 测试脚本记录器。最重要的事情是过滤掉所有你不感兴趣的请求。例如,记录图像请求是没有意义的(可以指示 JMeter 下载页面上的所有图像 - 请参阅 HTTP 请求 )。这些只会使你的测试计划变得混乱。最有可能的是,所有文件共享都有一个扩展名,例如.jsp、.asp、.php、 等。你应该通过输入.\*\\.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 访问。

没有安全保障。任何可以连接到端口的人都可以发出任何 BeanShell 命令。这些可以提供对 JMeter 应用程序和主机的不受限制的访问。 除非端口受到保护,例如防火墙,否则不要启用服务器。

如果你确实希望使用服务器,请在 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 脚本

从 JMeter 3.1 开始,我们建议从 BeanShell 切换到 JSR223 测试元素(有关更多详细信息,请参阅下面的 JSR223 部分),并从 __Beanshell 函数切换到 __groovy 函数。

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 都没有这样做,因此建议避免使用它们进行密集的负载测试。

注意:Beanshell 实现了 Compilable 接口,但它没有被编码——该方法只是抛出一个异常。JMeter 对此错误有一个明确的解决方法。

使用 JSR 223 元素时,建议检查 Cache compiled script if available 属性,以确保脚本编译在底层语言支持的情况下被缓存。在这种情况下,请确保脚本不使用任何使用${varName}的变量,因为缓存只会采用 ${varName} 的第一个值。而是使用:

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 并在后一个文件中进行

user.properties 文件取代了 jmeter.properties 中定义的属性

16.15 弃用的元素

建议不要使用不推荐使用的元素(在 更改列表组件参考 中标记为此类),并在可用时迁移到新的建议元素或做同样事情的新方法。
不推荐使用的元素从版本 N 的菜单中删除,但可以通过修改 user.properties 文件中的 not_in_menu 属性并从那里删除元素的完整类名来启用迁移。

请注意,版本 N 中已弃用的元素在版本 N+1 中肯定会被删除,因此请确保你尽快停止使用它们。