开源网络负载测试工具测评

译者注:当下有很多开源网络测试软件,当测试工程师在使用什么开源软件进行压测而没有依据时就很是烦恼。每个压测工具的功能覆盖维度,性能的优劣到底有什么不同。在国外有两篇写的很好的博客主要围绕这个问题展开而进行阐述。本文所讲述的主要围绕各主流测试工具而进行的,在经得Ragnar Lönn原博主允许的情况下进行的翻译。原文网址出处于:https://blog.loadimpact.com/open-source-load-testing-tool-review

编者注:我们在2018年12月4日更新了这篇博文,加入了k6开源负载测试工具。k6最初并没有包含在这个工具评论中,因为它是在博客首次发布之后发布的。

当下有非常多的网络性能负载测试工具,这些工具包括开源工具也包括闭源工具。在开源工具越来越受欢迎的现在,我们主要使用开源工具(Open-source Software)来进行负载压力测试。因此我们认为有必要针对当前主流的开源测试工具进行回顾,深入研究。以便选择哪个测试工具是最适合当前你所要进行的负载压力测试。(本次的工具回顾我们暂定其版本为v1.1)

OSS负载测试工具所提供的功能有很多,工具和工具之间在可用性,性能,工具本身的特性还有可靠性上差异会非常大。因此,我们希望通过该篇文章来帮助正在测试的你找到适合你所需要的测试工具。

本次的测评我们选择当今最流行的负载测试工具,这些工具包括如下:

  • Jmeter
  • Gatling
  • Locust
  • The Grinder
  • Apachebench
  • Artillery
  • Tsung
  • Vegeta
  • Siege
  • Boom
  • Wrk
  • k6 (Newly added to this review)

本文包含了我个人对这些负载测试工具优缺点的看法。基于基准测试的结果报告让大家对这些工具的性能和特性有一定的了解。

更新:如果你对针对测试工具的基准测试结果感兴趣可以在后续的基准测试报告中看到其结果报告。我们做了第二轮的基准测试,该测试中包含了我推荐的测试工具k6。

如何设置以达到负载测试工具之间性能的对比?

我们从命令行安装、配置然后运行这些测试工具。在尝试使用shell脚本和标准Unix工具提取被测性能工具的结果上花费了大量的时间。然后我们试着算出这些工具的相对性能。首先,通过手动运行每个工具尝试从每个工具中挤出最佳性能,优化被测工具的参数配置,然后在所有工具上运行基准测试,尝试以尽可能相似的配置运行被测工具。

由基准测试所得出的报告只是反映工具性能的一方面。但是在工具可用性方面我将由我实际使用体验给出评价意见。例如,一个工具在命令行中很难操作使用,或者当你按照测试工具指导运行测试后你很难得到一个有用的结果。遇到这种情况我就会发恼骚,并且写下来。这就是本文的全部内容。

一个重要的警告:我没有过多的研究每个测试工具的数据可视化的配置选项。如果你希望将测试工具产出的结果报告推送到数据存储服务器中或者是可视化系统中展现,你可能想了解每个测试工具在自动化配置的程度。
开源网络负载测试工具测评_第1张图片

你可以自己尝试在docker中运行这些测试工具

为了方便读者自己来尝试了解这些工具,我创建了一个公共的Docker镜像。它可以轻松重复我们所做的所有测试(或者只是运行其中的某一个负载测试工具。这样省去了自己安装这些测试工具的烦恼)。试试这个:

docker run -it loadimpact/loadgentest

如果你想在测试中增加网络延时,那么镜像参数的设置调整如下:

docker run -it --cap-add=NET_ADMIN loadimpact/loadgentest

当然你可以克隆我们Github的镜像源来构建你所需要的Docker镜像:

git clone https://github.com/loadimpact/loadgentest

在该链接中你可以找到一些文档来教你如何使用我们的Docker镜像。

测试工具选择

实际上,我给出一个简单的推荐建议,不如让我们看看我心目中排名前三的测试工具。我会给出为什么这些工具能排到前三名,并且会展示一系列的基准测试数据值。然后让你们决定你所需要的测试工具,因为每个测试工程师选取压测工具衡量的标准并不是唯一的。

开源软件测试工具前三排名–个人向

Gatling

Gatling工具的GitHub地址:http://gatling.io

开源网络负载测试工具测评_第2张图片
Gatling是一个很棒的负载测试工具,除开它的标准结果输出混乱程度和Locust有的一比。Gatling的表现虽然并不是很出色但是已经足够好了。Gatling工具的一致性设计使得它看起来很简洁,并且Gatling的文档做的比较完善。

Gatling提供DSL语言(领域专用语言),这种语言在Jmeter和Tsung工具中也有支持。虽然JMeter和Tsung使用XML来定义标记从而实现例如循环等功能。但是Gatling允许自定义Scala类,该类提供类似于JMeter和Tsung的DSL功能,但其语言可读性会更好。是的,Gatling通过Scala类来实现测试场景的构建。尽量使用Gatling的帮助文档来帮助你完成测试场景的定义。当你慢慢熟练时你会发现这并不是很复杂。

我最初以为Gatling使用起来会和JMeter一样笨拙,因为它是一个Java应用程序,并且具有与JMeter类似的DSL功能。但是在实际使用之后改变了我的想法,虽然我仍然非常喜欢使用“真实的”动态脚本语言来定义负载测试中的测试场景。Gatling的DSL可能是第二好用的动态语言(相对于真实的动态语言)。它是这样的:

 import io.gatling.core.Predef._
   import io.gatling.http.Predef._
   import scala.concurrent.duration._

   class GatlingSimulation extends Simulation {
      val httpConf = http
         .baseURL("http://myhost.mydomain.com")
         .disableCaching
         .acceptHeader("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
         .userAgentHeader("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0")
      val scn = scenario("My Scenario") // A scenario is a chain of requests and pauses
        .exec(http(“request_1”).get(“/index.html”))
        .pause(2)
        .exec(http(“request_2”).get(“/style.css”))
        .pause(5)
      setUp(scn.inject(atOnceUsers(100)).protocols(httpConf))
   }

我不打算讨论可视化,但是Gatling自动生成基于web的可视化测试结果,这相当不错。Gatling使用Highcharts图表库生成响应时间图。(我可以向想要创建任何类型图表的人推荐Highcharts库)。
Gatling默认生成有用的指标,例如几个不同的响应时间百分位数。 Gatling文档非常好,涵盖了您需要了解的大部分内容。Gatling允许您以制表符分隔格式将单个事务结果记录到日志文件中,从而可以轻松处理测试后结果并生成所需的任何度量标准。 我在Gatling和Jmeter上遇到的一个问题是我的指标无法获得比1ms更好的分辨率。 加特林日志看起来像这样:

REQUEST MyScenario 5 request_1 1474293386788 1474293386793 OK

Unix EPOCH的时间戳的精度就为毫秒,我不知道如何获取更高的时间精度分辨率。()当我在运行JMeter时,我尝试在命令行中使用-D sampleresult.useNanoTime=true参数来记录更为精确的时间精度,但是JMeter所打印的时间并没有更细微的变化。)
无论如何总结一下,我可以肯定一点:之前使用JMeter来进行负载测试,从事JAVA方面的工作人员,在使用JMeter之前先来看看这个工具慎重考虑一下还是否在选择JMeter来作为负载测试工具。对于我,一个饱受JVM折磨的人来说,Gatling需要JVM运行的事实仍然是一个很大的缺点。但是除此之外它是一个非常好的工具,感觉比Jmeter更加现代,并且有更好的用户体验。

K6

K6工具的网址链接如下
http://k6.io

我们已经写了关于为什么推荐使用k6工具的文章。为了快速理解K6的优势,我们总结为:K6是开发人员和DevOps团队为了将自动负载测试作为持续集成运行的一部分而所使用的最好工具。K6是由GO语言编写的,你可以使用JavaScript来编写测试用例。

K6引起了开发人员,测试人员和DevOps人员的浓厚兴趣,在Github上拥有超过4400标星。它运行很快(可以参见最新一版的基准测试数据)具有很好的API和基于UX的命令行。K6易于入门和使用,并且具有良好的文档管理。K6测试结果可以直接输出到stdout或者结果分析工具,例如 Load Impact Insights。

一下是使用K6测试工具JavaScript测试脚本的实例,其中使用阈值显示了通过/失败的测试结果,需要自动化其测试用例。

开源网络负载测试工具测评_第3张图片
由于k6使用ES6 JavaScript编写的负载测试用例,因此您的测试可以是模块化的。并且可以轻松导入标准库和自定义库。 k6可以加载ES6模块和ES5库。

内置模块:
0开源网络负载测试工具测评_第4张图片
k6可以导入远程托管的模块。 (此功能仅在本地从命令行使用k6测试时可用)。
导入远程模块:
开源网络负载测试工具测评_第5张图片
质量保证和性能工程团队可以使用Load Impact k6测试脚本记录器等工具创建真实的用户测试场景。k6在Load Impact Cloud Execution模式下运行,允许您在分布式云基础架构上运行大型负载测试,而无需自行管理该基础架构。 从最多10个不同的全局位置(加载区)生成负载。
如上所述,k6专为自动化而构建,并可集成到你的持续集成(CI)测试框架中。 与Jenkins,Circle CI,Team City和GitLab等CI工具集成。

有关更多的K6信息可以参阅一下链接:
k6的主站介绍
k6的官方文档
k6的GitHub网址

TSUNG

开源网络负载测试工具测评_第6张图片
TSUNG的官网地址如下:
Tsung - http://tsung.erlang-projects.org/

Tsung是用Erlang编写的,虽然我对Erlang的体验仅限于在路过偶尔看到别人屏幕时意外看到5-10行代码(代码看起来很奇怪),但我听到很多人都在谈论并发性有多好。这种说法似乎是真的,因为Tsung比我见过的任何其他工具更好地利用了多核CPU(即它在我的测试设置中完全使用了操作系统所有四个CPU内核)。 就产生的总流量而言,它也表现得非常好,与Jmeter相当。

Tsung支持多种协议,不仅仅是HTTP协议。 如果你想测一个WebDAV,XMPP,LDAP,SQL应用程序,那么Tsung会是一个很好的选择。 如果您有一些想要测试的其他四层应用程序,那么Tsung的插件可以支持原始TCP/UDP协议的应用程序测试。总体而言,Tsung的目标是良好的可扩展性和优秀的性能,同时还提供一完善的基本功能,其中包括您所需要的任何内容。

当您查看TSUNG的设计文档和说明文档时,在阅读整个文档中你能整体感受到这是一个非常有用的软件。TSUNG的入门可以说非常简单并且并不难掌握。

它主要缺点在于:Tsung生成虚拟用户用户场景使用XML编写的,这点就有点类似于JMeter。简单的Tsung配置文件如下:




    
    
    
    
    
    
    
    
    
    
    
        
    
    
    
    
        
        
            
        
        
    
    

尽管Tsung使用XML来编造测试场景,可以包含诸如循环体,if语句之类的东西。从而可以满足编写各种复杂的用户场景代码。但是Tsung缺乏动态脚本语言。Tsung的功能比较全面,但是可用性而言可能有些差强人意。很少有开发人员喜欢在XML中编程。 所以这一切都取决于你想执行的测试场景。 如果您不介意用XML指定用户场景,那么可以考虑使用一下Tsung,因为它是一个非常称职的软件,而不像JMeter那样难以学习和使用。

荣誉提名测试工具

The Grinder
我对The Grinder有两种想法。一方面,它看起来像一个古老而几乎死亡的项目。它于2000年首次发布,最新的正式版本发布于2012年。Grinder由Sourceforge托管。这些年谁知道在Sourceforge上主持Grinder的项目。 (我觉得这样说很糟糕,作为曾经的Sourceforge用户,并不应该这样说。Grinder完全没能保持相关性,并且错过了Git的迁移)。但是无论如何现在仍然有人在维护这个项目,并且每一年半会多多少少会有更新。你要说这个项目快死了吧,其实也还在那,并且还有新的代码提交。

另一方面Grinder是一个非常称职的负载测试工具,它开起来还是非常有用的。Grinder是少数几个支持使用动态语言的工具,您可以使用真实的动态编程语言在负载测试中定义虚拟用户行为。对于Grinder,默认脚本语言是Jython,它是Java运行的Python方言。据说,你也可以使用Clojure,虽然我不知道为什么要用Clojure。如果你熟悉Python,那么在Grinder的编程对你来说是小菜一碟。唯一的问题是你可能不能使用在Python环境所调用的庞大模块。 Jython是由一个Python标准库的继承实现的,所以Python其他库的支持性并不是很好。

尽管如此,它仍然是一个很好的和强大的语言,你可以做很多事情。下面是一个小型Grinder Jython文件的示例,该文件定义了负载测试期间虚拟用户行为:

   from net.grinder.script.Grinder import grinder
   from net.grinder.script import Test
   from net.grinder.plugin.http import HTTPRequest

   test1 = Test(1, "Request resource")
   request1 = HTTPRequest()
   test1.record(request1)

   class TestRunner:
     def __call__(self):
       result = request1.GET("http://myhost.mydomain.com/index.html")

如上所述,Python / Jython代码仅描述了虚拟用户在测试期间应该执行的操作。 测试范围的参数(如测试持续时间,负载水平等)在一个名为grinder.properties的单独文件中定义,该文件是一个非常标准的配置文件。该配置文件看起来如下所示(这仅仅是个示例,你可以配置更多的配置参数在里面):

   grinder.processes = 1
   grinder.threads = 20
   grinder.runs = 0
   grinder.useConsole = false
   grinder.script = /path/to/yourscript.py
   grinder.logDirectory = /var/log/grinder
   grinder.duration = 300000

(注意:grinder.duration以毫秒表示)
Grinder支持负载分配。 启动控制台进程,然后连接一个或多个远程代理进程。 反过来,建立代理的过程会创建工作进程来驱动虚拟用户。 Grinder在每个工作进程结束后将结果放入CSV样式的小文件中,这使得后续的结果处理相当简单。

Grinder就像Gatling和Jmeter一样,似乎无法产生分辨率高于1ms的结果。而这些工具它们都是Java应用程序。这些工具的JAVA的开发人员真的需要考虑一下,这个时间精度是否可以满足工具使用者的测试方案。

在许多复杂的实际设置中,1ms的时间精度可能就足够了。因为通常网络的响应时间将是几毫秒以上的。但我认为微秒级别的分辨率在越来越多测试场景中会有更多的价值。例如测量微服务的响应时间,客户端和服务端在同一个本地网络上。所以如果我今天编写一个新的负载测试工具,我肯定不会满足于1ms。

我起先认为Grinder失败的一个领域是其性能表现。鉴于它是一个旧的,有点过时的应用程序,加上它运行的是真正的动态脚本语言,其吞吐量(流量生成功能)将受到限制。但是我错了。它的性能表现得非常好,其性能几乎与Jmeter和Tsung等不执行“真正”代码的工具相提并论。令人印象深刻!

Grinder还有一个广泛可拓展的脚本类型的API接口,它允许您记录自定义指标等。总而言之,这是一个非常灵活和称职的工具,也表现良好。当然,由于Jython无法使用所有Python基础设施(模块)对某些人来说可能并不是一个好消息。

相对好用测试工具

有些工具还是相当不错的,我想在这里提一下。

Locust-(http://locust.io)

Locust是一个很棒的工具,应为开发Locust的开发人员显然考虑到其他开发者使用该测试工具。它允许您编写功能强大,富有表现力且易于理解的代码(实际应用代码,而不是笨重,有限,只限在DSL中使用的代码),用于定义负载测试中模拟用户的行为。 你编写普通的Python代码,谁不喜欢Python? 当然没有人!

这是一个非常简短的示例locustfile.py,它定义了测试中的虚拟用户应该执行的操作:

   from locust import HttpLocust, TaskSet

   def stylesheet(l):
     l.client.get("/style.css")

   class UserBehavior(TaskSet):
     tasks = {stylesheet:1}

   class WebsiteUser(HttpLocust):
     task_set = UserBehavior

在这种情况下,使用–host命令行选项在命令行上指定目标主机,而在Python代码中指定路径(“/style.css”)。这似乎是使用Locust执行操作的常用方法,但如果需要,您可以自由地在代码中指定所有内容。

Locust带有一个基于Web的小型命令和控制UI,并支持分布式负载生成,使其感觉非常可升级且具有前瞻性的。此外,locust.io网站显然是由一些有才华的设计师创建的 - 只要看看那个很酷的小昆虫标志!

但是,一旦你停止盯着他们闪亮的网站并开始真正使用该应用程序,你会发现它确实也有其弱点,就像其微小的昆虫一样。如果有一件事情Python无法满足,那可能就是高性能。而Locust则是一个Python应用程序。除了Python代码执行速度不快之外,Python GIL使得Locust很难使用多个单独的CPU,这意味着您必须运行多个进程来扩展负载生成。

事实证明,无论是Locust还是其他测试工具,产生在工具内部使用分布式产生负载是多么的重要。因为没有它,从用户的角度来看,应用程序多多少少缺少了可拓展性。许多人不需要进行大规模的测试,但至少要求能够在不需要切换工具的情况下完成项目测试。

那是不是即使使用单个CPU,Locust也应该能够产生相当多的流量,对吧?答案当然是:错误。在基准测试中,它比最快的测试工具慢大约25倍,因为它仅使用单个CPU(在基准测试中速度大约慢100倍,因为大多数其他工具能够在我的实验室中使用所有4个CPU产生负载)。

尽管如此,给定一台合理的机器,Locust每秒可生成数百数千个请求。这对于许多测试场景来说已经足够了。因此在排除Locust作为测试工具之前,你也可以不妨考虑考虑一下它。

Locust结果输出选项是比较受限的。如果您正在使用Web UI,则可以以CSV格式下载结果。但如果您使用命令行,则会得到一些不太漂亮的打印格式的结果,难以为人类和机器解析。我想你的目的是在Python代码中处理结果输出,这当然是可行的。但需要比较注意对结果的处理,否则Locust可能会进一步降低性能。并且在最坏的情况下会引入测量偏差。使用命令行选项以CSV或JSON格式存储详细结果是一个比较不错的选择。

Locust响应时间测量是众所周知的不可靠的,因为Locust为每次请求增加了许多内部延迟。这样只能查看运行不同负载测试之间的差异,而完全相信单次测试所给出的响应时间。或者您可以使用Locust进行负载生成,但使用其他方法(例如New Relic)测量响应时间。

那么,总结是什么呢?如果你主要以Python为编程语言,那么Locust可能就是你测试工具的选择之一。您将运行纯由Python开发的Locust,并可以使用所有标准Python模块等。但是,Locust在负载生成能力和测量精度方面是有很大的缺点。如果您只是喜欢Python并接受其他编程语言来进行测试,Grinder会提供Jython,它是Python-in-Java。尽管建议使用另一个Java应用程序(Grinder)。Grinder提供了一个很好的脚本语言,并且提供了相当不错的性能,尽管它是较旧的工具之一,并且没有像Locust那样频繁更新。

Artillery - http://artillery.io

Artillery很有意思,因为它似乎非常适合持续集成(CI)和自动化,很少有负载测试工具能够像它这样(或根本没有)对持续集成和自动化这么好的支持。 使用YAML或JSON配置Artillery并接收执行的负载测试结果。

Artillery在CircleCI或Travis测试套件中会非常好。 它还允许您执行自定义JS代码,并且提供YAML / JSON配置。 以下是一个Artillery JSON配置(在该配置中加上一个URL,成为我们用来运行基准测试的配置):

   {
     "config": {
       "target": "http://myhost.mydomain.com",
       "phases": [
         {"duration": 1, "arrivalRate": 20, "name": "startphase"}
       ]
     },
     "scenarios": [
       {
         "flow": [
           {
             "loop": [
               {"get": {"url": "/style.css"}}
             ],
             "count": 10000
           }
         ]
       }
     ]
   }

Artillery将测试结果保存为JSON格式的数据,并且有插件支持将结果发送到statsd,cloudwatch或InfluxDB。因此就结果输出而言该工具非常不错。虽然Artillery很棒,但是Artillery有几个原因没有成为我最终选择。

Artillery定义负载测试的方式非常适用于在用户场景中几乎没有事务交互的极其简单的场景测试中。这可能是99%的API测试者想要的?我不知道。但这意味着Artillery不适合更复杂的测试用例场景。

一个明显的缺点是无法控制测试执行时间。Artillery作者并没将测试执行时间暴露出来,就意味着测试时间不受控制。Artillery只是运行较短的用户场景,并且无法中断用户场景迭代。Artillery没有可以定义的全局测试持续时间参数。当有一个长期运行的用户场景(例如在基准测试中做一个无限循环,这种测试可被归类为“长时间运行”)。Artillery因为缺乏全局测试持续时间参数导致无法完全控制测试。如果要使用Artillery进行基准测试,并且能够像其他测试工具那样执行测试计划,这就必须限制每个VU的请求计数,这会导致VU在达到该请求目标数后退出从而结束测试计划。这种测试计划控制并不是很好,因为我无法精确制导整个测试在Artillery要运行多久。为此Artillery在整个计划测试过程中定义了“请求到达阶段”,虽然有些人可能会觉得这个设计很好,但是在我看来Artillery仍然缺乏有效的时间控制。

您不知道在测试运行的任何一个时刻Artillery具体执行了多少线程。如果用户场景更加复杂,则在要求的时间内可能无法执行完测试。Artillery另外一个缺点就是它的性能,如果要说有哪个测试工具不如它,那可能只有Locust。Artillery比Locust性能更佳,Artillery会为每个CPU核心产生更多的请求。但就像Locust一样,它不能为将CPU核心全部利用起来。与Locust不同,Artillery不支持内置的分布式负载生成(但Artillery好像正在准备开发)。这意味着原生Artillery只能使用一个CPU核心,除非说你可以对其进行二次化开发。

在基准测试设置中,Locust在一个CPU内核上运行时仅产生大约600-700 RPS,但可以在同一台机器上运行多个Locust线程,从而将性能提高到至少略高于2,000 RPS。Artillery在单核上产生的流量大约是Locust的两倍(~1400RPS),但因为没有分布式操作模式。在我进行基准测试对比的其余工具性能都有10,000+ RPS,因此在性能方面存在有更好的工具。

因此,Artillery无法产生大量的流量,而且测量精度也不是很好,这两个缺点和Locust差不多。在进行负载测试时,Artillery将会增大每次测量的延迟。如果测试工具的测量精度和大规模测试的能力对您很重要,那么Artillery不是一个很好的选择。

wrk-https://github.com/wg/wrk

Will Glozer创建了一个非常棒的wrk应用程序。我在这里提到它是因为它很简单,并且是性能最好的工具。在我们的实验室进行基准测试的设置当中,我们在压力机运行它时,目标机器以每秒约110,000个请求(RPS)速率而接近饱和(这里基准测试没有使用容器,使用容器会将所有工具的性能降低约40%)。此时压力机的CPU占50-60%,而接收端上所有四个CPU核心都忙于处理请求。这个性能是其他工具无法比拟的。

Wrk既可以在“静态”模式下运行,访问单个URL。也可以执行允许执行使用Lua代码的脚本语言。在我们的Docker容器化基准测试设置中,Wrk以大约60,000 RPS的访问单个静态URL的速度击败其他竞争工具。

Apachebench是在性能方面接近wrk的一个测试工具,在相同的测试场景下可以达到30-35,000 RPS。其他的测试工具Jmeter,Tsung,Grinder,Boom和Siege的性能都在15,000到30,000 RPS之间。有趣的是,在wrk执行Lua脚本时并没有带来过多的性能损耗。在使用Lua脚本编写的简单测试场景下获取的性能和访问一个静态页面的性能表现相差无几。

当一个工具是在一个方面的高度成熟通常意味着在其他方面有一定的牺牲。而Wrk也不例外,wrk会牺牲结果反馈。wrk只能获得整个测试的汇总结果,而缺少其他详细信息的报告。例如,没有关于您回复的响应代码的信息。

Wrk所支持的Lua脚本API是基于回调的,这意味着任何复杂的用户场景都不容易编写,并且您生成的代码也不容易阅读。以下一个非常简单的脚本示例:

   request = function()
     return wrk.format("GET", "http://myhost.mydomain.com/index.html")
   end

换句话说,API允许您定义Wrk在运行期间中调用某些Lua函数。 对于Wrk所发出的每个请求,都会调用一次“request”函数,并返回Wrk随后请求的URL。 这个API其实并不是太好用,在编写复杂的用户场景是将会变得和麻烦,所以不推荐使用。

Wrk是一个高流量负载生成工具,如果说你需要模拟并不是很复杂的访问流量并且对报告结果要求不高。

JMeter-http://jmeter.apache.org/

虽然JMeter绝对不是我最喜欢的测试工具,但仍然也要给予它很好的评价。因为它是一个非常称职的性能测试工具。与其他任何开源负载测试工具相比,JMeter集成了更完善的功能,并且它有更为广大的用户群体。

如果你是一个以Java为中心的组织,并且你也已经熟练使用JMeter。那么通过切换测试工具在短期上并不会有更好的收益提升。 JMeter可以测试多种不同的协议,它提供了良好的性能和可扩展性,并且具有完善的功能。JMeter主要的缺点在于基于XML的编程。所有的配置包括用户场景逻辑,都是用XML编写的。除了令人不愉快的配置之外,JMeter同样也有着令人感到不快的阅读感。如果您已经在使用JMeter,我会说最想让你换工具的原因有很大一点是将XMK更换为更为可读的,动态脚本语言。以下是JMeter的XML配置示例:

   
     
       
         
           
           false
           false
           
             
           
           
         
         
           
             continue
             
               false
               10000
             
             20
             1
             1406901208000
             1406901208000
             false
             
             
           
           
             
               
                 
               
               myhost.mydomain.com
               
               
               
               
               
               /style.css
               GET
               true
               false
               true
               false
               false
               
             
           
         
       
     
   

谁知到以上的内容在其他动态语言下可能会缩短很多代码,并且更加的可以阅读。另外一件事情是在运行JMeter需要熟悉Java应用程序和JVM的有关操作。当您尝试设置JMeter生成更多的负载时,似乎总会遇到一些麻烦。例如,在我尝试放宽系统限制(ulimt -v)时我遇到了一些奇怪但已知的JVM问题(请参阅https://bugs.openjdk.java.net/browse/JDK-8043516)。除非我设置了MaxHeapSize = …和-XX:CompressedClassSpaceSize = …,否者这个问题会导致Jmeter无法启动。在我看来,这是一个非常奇怪和不直观的bug。我通过不使用ulimit -v来设置最大虚拟内存大小而是修改系统有关默认值为我想要的值来解决这个bug。但是系统有关默认值与我尝试用ulimit设置的值相同。这种类型的问题比与JMeter相关的更多的是JVM / Java本身的问题。所以同样这些问题可能发生在Grinder和Gatling上。但比起Grinder和Gatling我觉得这类型的事情更常发生在JMeter上。 (尽管使用相同的JVM运行这三个工具,但这次我没有在Gatling或Grinder上遇到相同的问题。)

与其他工具相比,JMeter的入门也要相对困难。比较JMeter,Gatling和Grinder的入门介绍网页,不难发现JMeter的页面也是最长最复杂的。不过JMeter也是有很多优点的,它的性能良好,可配置性强,并且拥有庞大的社区。JMeter对用户的体验也并非很友好,因为JMeter是基于XML配置的DSL语言。如果不是使用Java应用程序的人很多,那估计很多人都会咒骂XML的这种设计。

Apachebench - http://httpd.apache.org/docs/current/programs/ab.html

Apachebench一点也不差。尽管只能使用1个CPU内核,AB的运行速度也非常快。AB的使用方法简单,并且提供了许多有用的选项。AB的结果报告有限,但也不会像wrk那样简陋。

如果你只是想要简单的压测一个URL并且期望这个工具功能俱全,那么Apachebench可能就是你的选择。起初我把Apachebench放在“其余工具”的部分,但我改变主意并决定将其置于“荣誉提名测试工具”之下。因为当你只想对一个URL进行单打单时,它确实是迄今为止最好的工具。我对Apachebench没有任何负面评价。它是一个专注于一项工作的工具,并且它做得非常好。

其余测试工具

现在对该篇文章未提及的工具来进行说明。这些工具中有些可能并不是很糟糕,有些工具只是说非常的具有特色而缺乏通用性从而使得不被广泛使用。

Vegeta - https://github.com/tsenart/vegeta

Vegeta有点类似于Artillery,因为它似乎面向自动化测试用例。vegeta没有VU /线程的概念,而是设置了目标请求率(每秒请求数)。在压测过程中Vegeta将尝试达到目标请求速率。vegeta没一个缓慢增加的缓冲区用来提高/降低请求速率。(译者注:vegeta设置的目标请求速率,只要压力机系统允许,就会尽可能的制造请求流量。这一点不像JMeter和loudrunner可以设置一个增长速率。)

这样的设计使得vegeta执行基准测试非常困难。在基准测试中我们必须尝试不同的静态请求率,并看看在哪里可以获得最大吞吐量而没有请求错误。 Vegeta的设计使它能够以在耗尽CPU系统资源之前按照指定的速率生成请求。由于vegeta花费了更多的CPU周期来生成更多的请求,这意味着指定过高的RPS数将导致成功请求的总数大幅下降。例如,除非您指定完全正确的请求率,否则您将无法知道Vegeta每秒可以实现的最大请求数。(译者注:这里其实是协调遗漏问题在作祟,如果超出了服务器的系统饱和值,越高的RPS和越长的测试时间只会带来越大的请求错误率。)

对于想要找出被测端最大吞吐量的测试场景来说,Vegeta可能不是一个很好的工具选择。但是如果你想在恒定负载下进行简单的静态URL测试,它可能是一个不错的选择。

Vegeta另一个令人讨厌设计是,虽然它可以指定并发连接数,但这些选项只配置的一个初始值。Vegeta会在测试运行时根据需要更改并发链接数。这意味着你唯一可以命令Vegeta做的事情是以一定的速率发送请求,其他参数取决于应用程序。在这些情况下,将其与其他负载测试工具进行比较非常困难。这点就像Artillery一样。

Vegeta很好地使利用了多核CPU架构系统,但在每个CPU使用效率上相当平均(这里效率指的是每个CPU核心可以输出多少流量)。它有相当多的命令行选项,可以使用这些命令从stdin读取URL执行各种操作。它支持HTTP / 2,并以二进制格式存储结果报告,然后您可以再次将其提供给vegeta以创建报告或以JSON/CSV格式输出结果。

vegeta README描述了如何使用Vegeta,并利用shell远程执行命令能力将压力机组合进行分布式测试。我确信这种方式有效,但几乎任何测试工具都可以做到这一点。所以我真的不能说Vegeta具有“分布式负载生成能力”(或者,从技术上讲,所有工具都具备这种能力)。

Vegeta有一点独特之处在于您也可以将它用为Go库,即您可以使用Vegeta库编写自己的负载测试工具。

Siege - https://www.joedog.org/siege-home/

Siege测试工具的使用体验着实令人沮丧。因为我将写下对Siege的评论,所系我需要向Siege的创作者Jeff Fulmer致歉。毕竟他为世界给了一个免费开源的测试工具可用。

Siege的主要优势在于它的工作原理很简单,并且在https://www.joedog.org/siege-manual/上提供了很好的在线手册。 但它有几个烦人的特点,这将使我只能将Siege作为最后的手段。 那么,siege为什么那么糟糕呢?

总体来说,Siege的设计和操作有点奇怪。通过Siege的文档你可能没有办法100%的去理解这个软件。这个软件可能需要在设计方面进行重构。比如在执行Siege是,它会告诉您已经完成的事物数量:

Transactions: 458 hits

然后它又会告诉您有多少成功的事物:

 Successful transactions: 471

为何事物数会低于成功事物数?这样的报告结果就显得没有意义了。我意识到有可能是我测试服务器对请求进行了重定向,这种重定向会影响Siege对事物的统计。在Seige网站文档上找到了答案“重定向被视为成功的事物”。很好,那问题来了。为什么我在这里成功事物数不是事物数的两倍?(因为每次请求都会产生一个301重定向,然后重定向的URL给出了200的响应)。在经过一番思考后,我想我已经理解了Seige是如何运作的了。在这里要理解“hit”的操作。“事物”并不指的是http请求-响应,而是请求命中web服务器。

当事务被认为是一个或多个HTTP请求 - 响应对,它们返回客户端想要的文件/资源​​,或者错误代码> = 400。当服务器返回3xx重定向时,它只被视为事务的额外中间步骤。

  1. “事物”值度量“非重定向”的响应代码的数量,即<300或> = 400
  2. “成功事物”指标必须通过以下方式计算:
    1. 看到的响应代码数量<300(请求成功)
    2. 尚未重定向的3xx重定向响应数量(我推测是请求重定向后,这些请求被记为“事物”,但不会被记为“成功事物”。)

在当今计算机和网络快速发展的现在,Seige的响应时间报告依然只给出以秒级为单位后小数点两位的报告。要知道有很多请求都能在1ms以内完成了。那么Seige在这种情况下报告能说明什么?

如果seige给出的报告的响应时间为“0.00秒”。相信我,这数据很有用。我一直在抱怨Java负载测试工具无法提供比1ms更好的分辨率,但现在我们有这样一个工具,在2017年了认为10ms仍然是一个非常好的时间精度。

在控制内部时延上Siege无法做得更好。在基准测试中表明Siege为每个请求增加了额外的时延。这个额外的延迟低于10毫秒,并且由你的网络时延而波动。即看起来Siege会为每个请求增加更多的延迟。如果源和目标机器之间的网络延迟很高,那么实际测试的延迟误差很低。

另外一个值得吐槽的地方时,Seige在指定时间单位上使用的是大写的“S”,同样分钟是大写的“M”,小时是大写的“H”。我从未在现代的测试工具当中有大写字母来度量时间单位的。我可能还处在一个VAX / VMS系统中,使用着OBOL或AS / 400 RPG程序。我问我们的开发人员他们是否读懂了这种表达时间的方式,有人回答说我说“30M”是不是代表“30个月”?

另外有一个问题是,在不同的系统上安装Seige,Seige会依据siegerc文件(/usr/local/etc/siegerc)和操作系统特性来配置Seige的默认值。在Seige网站主页和帮助文档中告诉你,如果在运行Seige命令行上没有指明的内容都会按照默认值来配置,但是你在实践中会发现默认值并不是按照文档所给出的那样来配置的。我不确定这是不是作者的数据,还是Seige的软件版本维护有问题,但它就是这样烦人。

最后一个问题是,Seige并不能保持高并发。如果你试图将并发性设置得太高,Siege会崩溃(当我使用它时,大约500 VU就会开始变得不稳定)。

在我看来,使用Siege的唯一原因是,如果你需要一个简单的Apachebench风格的工具,并且需要连续访问一系列的URL列表,而不仅仅是一个URL,那么你可以用Seige。

Boom - https://github.com/rakyll/boom

最后我评论的测试工具就是Boom。评论Boom时其实我在是在讨论的hey测试工具。只是因为我觉得hey作为一个负载测试工具的名字非常的愚蠢,所以我依然沿用这个测试工具旧的名字。如果你没搞懂我说的,只需转到上面的URL看一眼就知道了。 (当然,该URL会引导您访问https://github.com/rakyll/hey。)

Boom测试工具看上去很普通。它作为测试工具中规中矩,同时它并没有在任何领域有值得一提的地方。这是一个简单的工具。Boom README文档中声明Boom的目标是替换Apachebench。不幸的是,作者并没有想到拿什么去吸引已经在使用AB的人来使用Boom。

Boom表现得不错,但不如Apachebench,它的一般功能集比Apachebench更基本。但Boom支持HTTP / 2支持,并且它是用Go编写的。这可能会吸引Go社区用户来使用Boom。总而言之,如果你使用Go语言,那么使用Boom / Hey是没有问题的。如果你不是Go语言的使用者,请使用Apachebench。

Boom的非要和AB相比有的优势是:可以支持多核但Apachebench不能。

你可能感兴趣的:(网络,网络性能测试)