负载测试工具的对比

2023/05/12

一、简介

为工作选择正确的工具可能会令人生畏。在本教程中,我们将通过比较三个 Web 应用程序负载测试工具(Apache JMeter、Gatling 和 The Grinder)与一个简单的 REST API 来简化这一点。

2.负载测试工具

首先,让我们快速回顾一下每个方面的一些背景。

2.1。加特林

Gatling是一个负载测试工具,可以在 Scala 中创建测试脚本。Gatling 的记录器生成 Scala 测试脚本,这是 Gatling 的一个关键特性。 查看我们的 Gatling 简介 教程以获取更多信息。

2.2. JMeter

JMeter是 Apache 的负载测试工具。它提供了一个不错的 GUI,我们可以使用它来进行配置。称为逻辑控制器的独特功能为在 GUI 中设置测试提供了极大的灵活性。

请访问我们 的 JMeter 简介 教程以获取屏幕截图和更多说明。

2.3. 磨床

我们的最后一个工具The Grinder提供了比其他两个更基于编程的脚本引擎,并使用了 Jython。但是,The Grinder 3 确实具有录制脚本的功能。

Grinder 还与其他两个工具不同,它允许控制台和代理进程。此功能为代理进程提供了能力,以便负载测试可以跨多个服务器扩展。 它专门宣传为为开发人员构建的负载测试工具,用于发现死锁和减速。

3. 测试用例设置

接下来,对于我们的测试,我们需要一个 API。我们的 API 功能包括:

  • 添加/更新奖励记录
  • 查看一个/所有奖励记录
  • 将交易链接到客户奖励记录
  • 查看客户奖励记录的交易

我们的场景:

一家商店正在全国范围内进行销售,新客户和回头客需要客户奖励账户来节省开支。奖励 API 通过客户 ID 检查客户奖励帐户如果不存在奖励帐户,请添加它,然后链接到交易。

之后,我们查询交易。

3.1。我们的 REST API

让我们通过查看一些方法存根来快速了解 API:

@PostMapping(path="/rewards/add")
public @ResponseBody RewardsAccount addRewardsAcount(@RequestBody RewardsAccount body)

@GetMapping(path="/rewards/find/{customerId}")
public @ResponseBody Optional<RewardsAccount> findCustomer(@PathVariable Integer customerId)

@PostMapping(path="/transactions/add")
public @ResponseBody Transaction addTransaction(@RequestBody Transaction transaction)

@GetMapping(path="/transactions/findAll/{rewardId}")
public @ResponseBody Iterable<Transaction> findTransactions(@PathVariable Integer rewardId)
复制

请注意一些关系,例如通过奖励 id 查询交易和通过客户 id 获取奖励帐户 这些关系为我们的测试场景创建强制执行一些逻辑和一些响应解析。

被测应用程序还使用 H2 内存数据库进行持久化。

幸运的是,我们的工具都能很好地处理它,有些比其他的要好。

3.2. 我们的测试计划

接下来,我们需要测试脚本。

为了公平比较,我们将为每个工具执行相同的自动化步骤:

  1. 生成随机客户帐户 ID
  2. 发布交易
  3. 解析随机客户 ID 和交易 ID 的响应
  4. 使用客户 ID 查询客户奖励帐户 ID
  5. 解析奖励帐户 ID 的响应
  6. 如果不存在奖励帐户 ID,则添加一个带有帖子的帐户
  7. 使用交易 ID 发布相同的初始交易并更新奖励 ID
  8. 通过奖励账户id查询所有交易

让我们仔细看看每个工具的第 4 步。并且,请务必查看所有三个已完成脚本的示例

3.3. 加特林

对于 Gatling 而言,熟悉 Scala 为开发人员带来了福音,因为 Gatling API 很健壮并且包含很多特性。

Gatling 的 API 采用了构建器 DSL 方法,正如我们在其第 4 步中所见:

.exec(http("get_reward")
  .get("/rewards/find/${custId}")
  .check(jsonPath("$.id").saveAs("rwdId")))
复制

特别值得注意的是,当我们需要读取和验证 HTTP 响应时,Gatling 对 JSON 路径的支持。在这里,我们将获取奖励 id 并将其保存到 Gatling 的内部状态。

此外,Gatling 的表达式语言使动态请求正文字符串更容易:

.body(StringBody(
  """{ 
    "customerRewardsId":"${rwdId}",
    "customerId":"${custId}",
    "transactionDate":"${txtDate}" 
  }""")).asJson)
复制

最后是我们用于此比较的配置。1000 次运行设置为整个场景的重复,atOnceUsers 方法设置线程/用户:

val scn = scenario("RewardsScenario")
  .repeat(1000) {
  ...
  }
  setUp(
    scn.inject(atOnceUsers(100))
  ).protocols(httpProtocol)复制

整个Scala 脚本 可在我们的 Github 存储库中查看。

3.4. JMeter

JMeter 在 GUI 配置后生成一个 XML 文件。该文件包含具有设置属性及其值的 JMeter 特定对象,例如:

<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Add Transaction" enabled="true">复制
<JSONPostProcessor guiclass="JSONPostProcessorGui" testclass="JSONPostProcessor" testname="Transaction Id Extractor" enabled="true">复制

查看testname属性,当我们识别出它们与上述逻辑步骤匹配时,它们可以被标记。添加子项、变量和依赖项步骤的能力为 JMeter 提供了脚本所提供的灵活性。此外,我们甚至设置了变量的范围!

我们在 JMeter 中运行和用户的配置使用ThreadGroups

<stringProp name="ThreadGroup.num_threads">100</stringProp>复制

查看整个 jmx文件作为参考。虽然可能,但在 XML 中将测试编写为.jmx文件对于功能齐全的 GUI 没有意义。

3.5. 磨床

如果没有 Scala 和 GUI 的函数式编程,我们的 The Grinder 的 Jython 脚本看起来非常基础。添加一些系统 Java 类,我们的代码行数就会少很多。

customerId = str(random.nextInt());
result = request1.POST("http://localhost:8080/transactions/add",
  "{"'"customerRewardsId"'":null,"'"customerId"'":"+ customerId + ","'"transactionDate"'":null}")
txnId = parseJsonString(result.getText(), "id")复制

但是,更少的测试设置代码行需要更多的字符串维护代码(例如解析 JSON 字符串)来平衡。此外,HTTPRequest API 的功能也很精简。

使用 The Grinder,我们在外部属性文件中定义线程、进程和运行值:

grinder.threads = 100
grinder.processes = 1
grinder.runs = 1000复制

我们为 The Grinder 编写的完整 Jython 脚本将如下所示

4. 试运行

4.1。测试执行

这三个工具都建议使用命令行进行大型负载测试。

为了运行测试,我们将使用 Gatling开源版本 3.4.0 作为独立工具、JMeter 5.3和 The Grinder版本 3

Gatling 只需要我们 设置 JAVA_HOMEGATLING_HOME。要执行 Gatling,我们使用:

./gatling.sh复制

在 GATLING_HOME/bin 目录中。

JMeter在启动GUI进行配置时需要一个参数来禁用测试的GUI:

./jmeter.sh -n -t TestPlan.jmx -l log.jtl复制

与 Gatling 一样,The Grinder 要求我们设置JAVA_HOMEGRINDERPATH。但是,它还需要更多属性:

export CLASSPATH=/home/lore/Documents/grinder-3/lib/grinder.jar:$CLASSPATH
export GRINDERPROPERTIES=/home/lore/Documents/grinder-3/examples/grinder.properties复制

如上所述,我们提供了一个grinder.properties文件用于附加配置,例如线程、运行、进程和控制台主机。

最后,我们使用以下命令引导控制台和代理:

java -classpath $CLASSPATH net.grinder.Console复制
java -classpath $CLASSPATH net.grinder.Grinder $GRINDERPROPERTIES复制

4.2. 试验结果

每个测试使用 100 个用户/线程运行 1000 次。让我们解开一些亮点:

  成功的请求 错误 总测试时间(秒) 平均响应时间(毫秒) 平均吞吐量
加特林 500000 个请求 0 218s 42 2283 个请求/秒
JMeter 499997 个请求 0 237s 46 2101 个请求/秒
磨床 499997 个请求 0 221s 43 2280 个请求/秒

结果显示这 3 个工具具有相似的速度,基于平均吞吐量,Gatling 略微超过其他 2 个。

每个工具还在更友好的用户界面中提供附加信息。

Gatling 将在运行结束时生成一个 HTML 报告,其中包含多个图表和统计信息,用于总运行以及每个请求。以下是测试结果报告的片段:

加特林结果新 1

使用 JMeter 时,我们可以在测试运行后打开 GUI,并根据我们保存结果的日志文件生成 HTML 报告:

2020/10/jmeter-result-new.png

JMeter HTML 报告还包含每个请求的统计信息细分。

最后,Grinder 控制台记录每个代理的统计信息并运行:

研磨机结果新 1

虽然 The Grinder 是高速的,但它的代价是额外的开发时间和更少的输出数据多样性。

五、总结

现在是时候全面了解每个负载测试工具了。

  加特林 JMeter 磨床
项目和社区 9 9 6
表现 9 8 9
脚本能力/API 7 9 8
用户界面 9 8 6
报告 9 7 6
一体化 7 9 7
概括 8.3 8.3 7

加特林:

  • 可靠、完善的负载测试工具,可使用 Scala 脚本输出漂亮的报告
  • 产品的开源和企业支持级别

JMeter:

  • 用于测试脚本开发的强大 API(通过 GUI),无需编码
  • Apache Foundation 支持以及与 Maven 的出色集成

研磨机:

  • 为使用 Jython 的开发人员提供的快速性能负载测试工具
  • 跨服务器可扩展性为大型测试提供了更多潜力

简而言之,如果需要速度和可扩展性,请使用 The Grinder。

如果漂亮的交互式图表有助于显示性能提升以支持更改,那么请使用 Gatling。

JMeter 是用于复杂业务逻辑的工具或具有多种消息类型的集成层。作为 Apache 软件基金会的一部分,JMeter 提供了成熟的产品和大型社区。

六,结论

总之,我们看到这些工具在某些领域具有类似的功能,而在其他领域则大放异彩。正确工作的正确工具是适用于软件开发的口语智慧。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章