写点什么

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:0014963

评论 1 条评论

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

什么是区块链dapp开发?它能做什么?

区块链软件开发推广运营

交易所开发 dapp开发 链游开发 公链开发 代币开发

网站做IPv6改造前需要哪些准备工作?

国科云

KubeCon Europe 2025 | 一图速览华为云精彩议程

华为云原生团队

云计算 容器 云原生

【大模型加速器2.0】合合信息文档图表解析全方位深度测评

申公豹

ORC技术

天润融通助力扬子空调AI升级客服系统,独立解决率飙升至45%

天润融通

MacBook 跑通 : Deep Research

Lily

医疗场景实战:百条数据 RFT 微调盘古大模型,精度大幅提升

华为云开发者联盟

人工智能 LLM 华为云盘古大模型

【HarmonyOS Next】鸿蒙应用弹框和提示气泡详解(二)之浮层(OverlayManager),半模态页面(bindSheet),全模态页面(bindContentCover)详解

GeorgeGcs

模态 OverlayManager bindContentCover bindSheet 浮层

揭秘淘宝拍立淘API:开启智能商品搜索新时代

Noah

AI+低代码:企业数字化转型的双引擎

万界星空科技

AI 低代码 低代码平台 mes 万界星空科技低代码平台

25年什么样的 Agent 会脱颖而出:简单胜于复杂

极客天地

Rust 与 FFmpeg 实现视频水印添加:技术解析与应用实践

Yeauty

rust ffmpeg Video media audio

Rust + TDengine:打造高性能时序数据处理利器

TDengine

tdengine 数据库·

Go 语言常见错误——并发编程

FunTester

三级等保测评的云

黑龙江陆陆信息测评部

智能感知的未来:传感器融合与数字样机技术

DevOps和数字孪生

交易所开发的实践与展望

区块链软件开发推广运营

交易所开发 dapp开发 链游开发 公链开发 代币开发

新闻速递丨数字化再升级:Altair One 云端门户与 NVIDIA Omniverse 实时数字孪生蓝图完成全面整合

Altair RapidMiner

AI HPC 数字孪生 仿真 AltairOne

第八届中国国际管道会议(CIPC)现已开启观众登记通道

江湖老铁

直播分享|TinyPro:一行命令,搭建包含前后端的后台管理系统

OpenTiny社区

开源 前端 OpenTiny TinyPro 中后台系统

签约快讯|天润融通签约石头科技

天润融通

HPE Aruba Networking助力电信运营商和企业加速创新,拥抱AI市场变革新机遇

科技热闻

从 MySQL 到时序数据库 TDengine:Zendure 如何实现高效储能数据管理?

TDengine

tdengine 时序数据库 数据库·

社会福利机构一定要买堡垒机吗?取决于什么因素?

行云管家

等保 堡垒机 社会福利

Google 发布 Gemini 2.5 Pro 模型:思考+多模态;Vibe Coder :通过语音对话实现「氛围编程」丨日报

声网

万字详解主权跨链代币标准「ERC-7281」,如何让跨链代币具有可互换性?

TechubNews

2025 全球人形机器人赛道大事件解读和发展趋势分析!!

机器人头条

科技 大模型 人形机器人 具身智能

原生APP和混合APP的开发方式

北京木奇移动技术有限公司

软件外包公司 APP外包公司 APP开发公司

告别分库分表,时序数据库 TDengine 解锁燃气监控新可能

TDengine

tdengine 时序数据库

APP开发的框架

北京木奇移动技术有限公司

软件外包公司 APP外包 APP开发公司

25年深圳企业办理等保合规流程指南

行云管家

网络安全 信息安全 等保

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