阿里、蚂蚁、晟腾、中科加禾精彩分享 AI 基础设施洞见,现购票可享受 9 折优惠 |AICon 了解详情
写点什么

Gatling 与 JMeter,性能测试工具该选谁

作者:Andrzej Ludwikowski

  • 2022-08-03
  • 本文字数:5165 字

    阅读完需:约 17 分钟

Gatling与JMeter,性能测试工具该选谁

JMeterGatling是性能测试工具中的佼佼者。现在已经有很多关于比较这两个工具的文章,那么为什么我还要再这篇文章呢?我将从一个不一样的角度来比较这两个工具。这两个工具我都用了很长一段时间了,我想是时候总结一下我的经验了。

完美的性能测试应该是怎样的

 

从开发人员的角度来看,测试应用程序的性能是开发人员的职责。因此,让一个从未接触过应用程序源代码的测试团队来测试应用程序的性能,这种方法是行不通的。我并不是说测试人员就无法进行良好的性能测试,我想强调的是,如果我们有专门的性能测试人员,那么从一开始就应该让测试人员和开发人员进行密切的合作。

 

随着时间的推移,越来越多的责任会转移到测试团队,但开发人员仍然需要对结果进行分析。当结果与我们最初的预期不同时,就尤为如此。当然,这对开发人员来说是有好处的,因为它创建了一个与解决方案质量相关的反馈循环,类似于单元测试、集成测试或端到端(E2E)测试。

 

性能测试无疑是软件开发当中成本最高的一种测试。测试人员或开发人员需要花宝贵的时间创建它们,除此之外,它们还需要一个专门的(如果可能的话)测试环境。应用程序的变化非常频繁,性能测试需要跟踪这些变化,并保持最新,这比最初创建测试时的成本更高。

 

基于上述原因,关于性能测试,我的第一个建议是用长期的思维来考虑整个测试过程。理想情况下,性能测试应该是持续部署(CD)的一部分。但这并不一定总能实现,也并不一定是有意义的。然而,根据我的观察,在一开始的性能测试中走捷径可能会让我们在未来付出更大的代价。

如何选择性能测试工具

 

选择性能测试工具是第一个难题,我希望本文能够帮助你做出正确的选择。

 

从开发人员的角度来看,一个好的性能测试工具应该具备以下四个主要属性。

 

  1. 可读性;

  2. 可组合性;

  3. 正确的指标;

  4. 分布式负载生成。

 

你可能会说:“就这样?”是的。这些是在选择工具时最重要的考虑因素。当然,还有很多其他特定的功能,尽管大多数工具在创建测试场景、模拟流量等方面提供了或多或少类似的选项。所以,在选择一个既方便又可维护的工具时,我会把重点放在这些要点上。

 

只有当一个工具满足了这四个基本要求,我们才能继续了解它提供的其他功能。否则,如果只是受到一些有趣功能的诱惑,从长远来看,这些功能可能既不有趣也不是很有用,它将变成一个不那么好的工具。

可读性

 

我们先从第一点开始。比较带有 GUI 的应用程序的可读性是一种非常不寻常的方法,我们来看看它会产生怎样的结果。JMeter 中的一个简单的业务流程可能如下所示。


 

乍一看,相当不错。一切都很清楚,我们很容易就可以理解测试的是什么。问题是,随着我们开始扩展场景,添加新的测试步骤,参数化当前步骤或改变它们的行为,那么很快,我们就会得出这样的结论:这是一项非常乏味的工作。你必须经常使用鼠标,知道什么东西藏在哪里,更糟糕的是,你需要记住各个查询之间的隐式连接(例如,共享变量)。

 

根据我的经验,在 GUI 上编辑测试用例迟早会变得不那么令人感到愉快,我们将切换到编辑 XML 格式的源代码,而 XML 格式的源代码(通常是 XML 格式)可读性很差。在 XML 中,我们能够做的就是使用最基础的基于字符串的编辑技术,例如“替换”等。

 

<?xml version="1.0" encoding="UTF-8"?><jmeterTestPlan version="1.2" properties="5.0" jmeter="5.3"></jmeterTestPlan>  <hashTree></hashTree>    <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan" enabled="true"></TestPlan>      <stringProp name="TestPlan.comments"></stringProp>      <boolProp name="TestPlan.functional_mode">false</boolProp>      <boolProp name="TestPlan.tearDown_on_shutdown">True</boolProp>      <boolProp name="TestPlan.serialize_threadgroups">false</boolProp>      <elementProp name="TestPlan.user_defined_variables" elementtype="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true"></elementProp>        <collectionProp name="Arguments.arguments"></collectionProp>      </elementProp>      <stringProp name="TestPlan.user_define_classpath"></stringProp>      ...	  That's a very, very long XML.      ...
复制代码

 

完整的 XML 代码在这里

 

在 Gatling 中,同样的场景看起来像这样。

  val scn =    scenario("Example scenario")      .exec(http("go to main page").get("/"))      .exec(http("find computer").get("/computers?f=macbook"))      .exec(http("edit computer").get("/computers/6"))      .exec(http("go to main page").get("/"))      .repeat(4, "page") {        exec(http("go to page").get("/computers?p=${page}"))      }      .exec(http("go to create new computer page").get("/computers/new"))      .exec(        http("create new computer")          .post("/computers")          .formParam("name", "Beautiful Computer")          .formParam("introduced", "2012-05-30")          .formParam("discontinued", "")          .formParam("company", "37")      )
复制代码

 

它与 JMeter 非常相似,也就是说,你可以看到正在测试的内容以及整体流程。不过,我们不要忘了,这段源代码的可读性几乎和普通语句一样。我们首先会想到的是,既然是源代码,那么我们就可以使用所有已知的重构方法来扩展场景或提高其可读性。

 

Scala(Gatling 中使用的是 Scala)是一种高度类型化的语言,构造场景的大多数问题将在编译代码时被发现。而在 JMeter 中,只有当场景启动时才会检查错误,这肯定会降低结果反馈循环的速度。

 

源代码的另一个好处是,测试的版本管理将变得非常容易,并且可以让其他程序员(甚至是来自不同的团队)评审它们。如果你不得不面对数千行 XML,那么只能祝你好运。

可组合性

 

如果我们需要创建多个共享某些逻辑的性能测试,例如身份验证、用户创建等,可组合性是至关重要的。在 JMeter 中,我们只能通过非常快速的复制粘贴来编辑这些测试。即使是这个简单的测试也存在重复的片段。



随着时间的推移,需要重复的地方会越来越多。不仅是单个请求,整个业务逻辑片段都需要被复制。你可以使用Module Controller来解决这个问题,或者用 Groovy 或 BeanShell 创建自己的扩展。从我的经验来看,这样做非常不方便而且容易出错。

 

在 Gatling 中,构建可重用的片段基本上只受编程技能的限制。第一步是提取出一些可以被多次使用的方法。

 

  private val goToMainPage = http("go to main page").get("/")

private def findComputer(name: String) = http("find computer").get(s"/computers?f=${name}")

private def editComputer(id: Int) = http("edit computer").get(s"/computers/${id}")

private def goToPage(page: Int) = http("go to page").get(s"/computers?p=${page}")

private val goToCreateNewComputerPage = http("go to create new computer page").get("/computers/new")

private def createNewComputer(name: String) = http("create new computer") .post("/computers") .formParam("name", name) .formParam("introduced", "2012-05-30") .formParam("discontinued", "") .formParam("company", "37")

val scn = scenario("Example scenario") .exec(goToMainPage) .exec(findComputer("macbook")) .exec(editComputer(6)) .exec(goToMainPage) .exec(goToPage(1)) .exec(goToPage(1)) .exec(goToPage(3)) .exec(goToPage(10)) .exec(goToCreateNewComputerPage) .exec(createNewComputer("Awesome computer"))
复制代码

 

接下来,我们可以将场景划分为更小的片段,然后组合它们并创建出更复杂的业务流程。

 

  val search = exec(goToMainPage)    .exec(findComputer("macbook"))    .exec(editComputer(6))

val jumpBetweenPages = exec(goToPage(1)) .exec(goToPage(1)) .exec(goToPage(3)) .exec(goToPage(10))

val addComputer = exec(goToMainPage) .exec(goToCreateNewComputerPage) .exec(createNewComputer("Awesome computer"))

val scn = scenario("Example scenario") .exec(search, jumpBetweenPages, addComputer)
复制代码

 

如果我们需要长期维护性能测试,那么毫无疑问,与其他工具相比,高可组合性将是一个优势。根据我的观察,似乎只有那些支持通过源代码来编写测试用例的工具,例如 Gatling 和 Scala、Locust和 Python、WRK2和 Lua 符合这个标准。如果测试用例是用 XML、JSON 等文本格式保存的,那么可组合性总是会受到这些格式的限制。

正确的指标

 

每一个性能测试人员应该都听到过这个说法:“谎言、该死的谎言和统计数据。”如果他们还没听到过,那么他们肯定会以一种非常痛苦的方式学上一课。我们可以用一整篇文章来讨论为什么这句话会成为性能测试领域的咒语。简而言之:中位数、算术平均值、标准偏差在这个领域是完全无用的指标(你只能把它们当作额外的见解)。你可以在 Gil Tene(Azul 的首席技术官和联合创始人)的精彩演讲中获得更多细节。因此,如果性能测试工具只提供这种静态数据,那么你可以立即把它丢掉。

 

衡量和比较性能的唯一有意义的指标是百分比,但在使用它们时要注意它们是如何实现的。通常,它们是基于算术平均值和标准偏差实现的,这导致它们变得不那么有用。

 

你可以从上面的演讲视频中学习如何验证百分比的正确性。

 

另一种方法是自己检查实现指标的源代码。但遗憾的是,大多数性能测试工具文档并没有涵盖如何计算百分比。即使有这样的文档,也很少有人会去阅读它,因此可能会掉入一些陷阱,例如Dropwizard框架指标的实现

 

如果没有正确的数学/统计数据,我们在性能测试方面所做的工作都是毫无价值的,因为我们将无法理解单个测试的结果或结果之间的比较。

 

我在进行性能测试时通常会使用百分比可随着时间发生变化的图形,Gatling 和 JMeter 都提供了这些功能。我们因此能够判断被测试的系统在整个测试过程中是否存在性能问题。



要比较各个测试的结果,你需要使用全局百分比(在两个工具中都可用)。但 JMeter 全局百分比的准确性可能是个问题。Gatling 使用HdrHistogram库来计算百分比,在准确性和内存需求之间做出了一个非常合理的折衷。

分布式测试

 

有一些文章讨论了测试工具本身的性能。这在一定程度上也很重要,因为我们需要生成巨大的流量给被测试的系统“施压”。问题在于,现在的应用程序很少是运行在单台机器上的单个实例。我们测试的是包含多个实例的分布式系统,这些实例运行在不同的机器上(通常是动态可伸缩的云解决方案)。单台机器的性能测试无法生成足够的负载来测试这样的环境。因此,我们不应该去关注哪个工具可以在一台机器上产生更多的流量,而是看看有没有可以同时从多台机器运行分布式测试的工具。

 

在这方面,这两个工具打成了平手。我们可以在 Gatling 和 JMeter 中进行手动的分布式测试。此外,我们可以使用现有的解决方案,如FloodGatling Enterprise,为我们自动完成分布式测试。我绝对推荐后者,因为它会为我们节省很多宝贵的时间。

总结

 

尽管本文的基调可能会被认为是在嘲讽 JMeter,但这并不是我的本意,因为这两种工具我都用过。我曾经以为 JMeter 是唯一合理的测试性能工具,但当我开始使用 Gatling 时,我看不到再回到 JMeter 的意义。

 

一个带有图形界面的工具在一开始可能会更容易使用,但对于我来说,将性能测试作为代码的想法更有吸引力。Gatling 的 DSL 使用起来非常方便,具有很强的可读性,维护起来也容易得多。

 

很多人对 Gatling 持怀疑态度,因为它要求学习一门新的编程语言——Scala,而 Scala 被认为是一门很难使用的编程语言。然而,事实并非如此。Scala 有其优点和缺点,要在 Gatling 中使用 Scala,只需要掌握基本的语法知识即可。另外,如果你一直希望在工作中使用 Scala,但由于各种原因无法实现,那么性能(和自动化)测试将是一个将这门语言引入你的生态系统的绝佳机会。需要注意的是,从 Gatling 3.7 开始,你可以使用 Java 了!这将是我下一篇文章的主题。请继续关注。

 

作者简介:

Andrzej Ludwikowski 是SoftwareMill的软件架构师,拥有超过 12 年的商业软件开发经验。他是技术会议发言人和博客作者,领域驱动开发、事件溯源和多语言持久化技术爱好者,喜欢研究系统性能瓶颈问题。他有一个不断追求完美软件架构的梦想,尽管这样的架构可能不存在,但追求梦想本身就是目标。他还是 SoftwareMill Academy 的培训师。

 

原文链接

Gatling vs JMeter - What to Use for Performance Testing

 

2022-08-03 08:0011759

评论 1 条评论

发布
用户头像
图形工具的短板就是与其他工具得交互,及自身的自动化。
2022-09-30 10:17 · 北京
回复
没有更多了
发现更多内容

软件测试/测试开发/全日制 | 从前端到后端:Python全栈开发的入门指南

测吧(北京)科技有限公司

测试

软件测试/测试开发|什么是pytest,我们为什么选择pytest?

霍格沃兹测试开发学社

软件测试/测试开发/全日制 | Python全栈开发中的WebSocket实践:实现实时通信和互动性

测吧(北京)科技有限公司

测试

软件测试/测试开发/全日制 | 学习使用ORM简化数据库操作

测吧(北京)科技有限公司

测试

Databend 的算力可扩展性

Databend

Lazada商品详情API(lazada.item_get)获取商品的评论和评分信息

技术冰糖葫芦

API

低代码:实现数据可视化的强大助手

不在线第一只蜗牛

数据库 低代码 数据可视化

软件测试/测试开发/全日制 | 深度学习的崛起与在人工智能中的关键作用

测吧(北京)科技有限公司

测试

软件测试/测试开发/全日制 | 人工智能的基本概念与发展趋势

测吧(北京)科技有限公司

测试

软件测试/测试开发/全日制 | 机器学习的原理与应用:算法驱动的智能革命

测吧(北京)科技有限公司

测试

软件测试/测试开发/全日制 | Python全栈开发之路:HTML/CSS/JavaScript基础深度学习

测吧(北京)科技有限公司

测试

图形工作站有必要么?图形工作站电脑特点

青椒云云电脑

图形工作站 移动图形工作站

2023 年最先进认证方式上线,Authing 推出 Passkey 无密码认证

Authing

身份认证 Authing 无密码认证 Passkey

老生常谈:Web 与低代码开发

快乐非自愿限量之名

Web 前端开发 低代码 开发

软件测试开发/全日制丨软件开发流程 学习笔记

测试人

软件测试

深耕汽车检测设备领域,引领行业技术革新

Geek_2d6073

一文解释Linux的内存分页管理

伤感汤姆布利柏

Vue3构建的低代码可视化平台

高端章鱼哥

Vue 低代码 前端框架 JNPF

OpenTiny 2023年度共建者榜单大曝光!!!

OpenTiny社区

开源 前端

体育直播平台系统源码:如何有效防止后门、恶意代码和漏洞

软件开发-梦幻运营部

云消息队列 Kafka 版生态谈第一期:无代码转储能力介绍

阿里巴巴云原生

kafka 阿里云 Serverless 云原生

字节跳动 Spark 支持万卡模型推理实践

字节跳动云原生计算

机器学习 spark 云原生

2024年区块链行业发展,项目涵盖内容

区块链软件开发推广运营

dapp开发 区块链开发 链游开发 NFT开发 公链开发

软件测试/测试开发|什么是Python,我们为什么选择Python?

霍格沃兹测试开发学社

软件测试/测试开发/全日制 | 数据交互与通信:Python全栈开发必备的HTTP知识

测吧(北京)科技有限公司

测试

软件测试/测试开发/全日制 | 从Ajax到WebSocket:Python全栈开发中的前后端通信技巧

测吧(北京)科技有限公司

测试

lazada商品列表数据接口(lazada.item_search)丨lazada API接口

tbapi

lazada商品详情数据接口 lazada商品数据接口 lazada API接口 lazada商品列表数据接口

摆脱自研难题,AUI Kit助力企业快速搭建专属互动课堂

阿里云视频云

云计算 视频云

如潮好评!优秀选手视角下的第二届粤港澳大湾区(黄埔)国际算法算例大赛

ModelWhale

人工智能 大数据 算法赛 粤港澳大湾区 算法开发

软件测试/测试开发全日制培训|Pytest跳过用例和失败重试

霍格沃兹测试开发学社

软件测试/测试开发/全日制 | 自然语言处理技术在人工智能时代的崛起与发展

测吧(北京)科技有限公司

测试

Gatling与JMeter,性能测试工具该选谁_软件工程_InfoQ精选文章