7

性能框架哪家强—JMeter、K6、locust、FunTester横向对比 - InfoQ 写作平台

 3 years ago
source link: https://xie.infoq.cn/article/e5a8e9a651c2de86bb3e344e7?
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

性能框架哪家强—JMeter、K6、locust、FunTester 横向对比

发布于: 2021 年 07 月 11 日

经过了之前的铺垫:性能测试框架对比初探,目前留下来的几个测试框架就是 JMeterK6locust FunTester。本次测试目的是对比几种框架的在各个并发下面的发压能力和资源消耗。本次值测试了最简单的GET接口,不涉及参数和POST接口。

先说结论:

  • 低并发(100 线程)情况下,FunTester 资源消耗略微占优,但是高并发(200 线程)情况下 K6 牛逼,golang还是比较狂野,优势明显。

  • 在尚未达被测服务性能拐点的时候,FunTester 测试框架在资源消耗还有一些优势,但是达到拐点之后,由于线程的频繁上下文切换,K6 的优势就非常明显了,总体来看大概两倍的差距。

  • 本地测试也验证了上面两点,不过被测服务的 QPS 达到 6 万+,而局域网被测服务最高 1.5 万徘徊。

本机硬件2.6 GHz 六核Intel Core i7,CPU 统计数据来自活动监视器100%代表消耗了一个 CPU 线程,理论上全部 CPU 资源当做1200%,内存数据也来自活动监视器

首先我利用FunTester moco server框架架构图测试框架在局域网环境起了一个测试服务,只有一个兜底接口。Groovy脚本如下:

import com.mocofun.moco.MocoServerclass TestDemo extends MocoServer{    static void main(String[] args) {        def log = getServerNoLog(12345)        log.response("hello funtester!!!")        def run = run(log)        waitForKey("fan")        run.stop()    }}

同一局域网服务的性能没有问题的,跟本地启动服务区别在于,本地请求太快了,各种框架压测差不不够明显。而且测试本地服务,QPS 太高平均响应时间太低了,导致误差会比较大。

locust

本地Python版本 3.8locust默认下载版本:locust 1.5.3

locust框架只需要一个写好的Python脚本,下面分享一下测试脚本。

第一版非常基础,但是实测太拉胯了,如下:

from locust import HttpUser, TaskSet, taskclass UserBehavior(TaskSet):    @task(1)    def profile(self):        self.client.get("/m")class WebsiteUser(HttpUser):    tasks = [UserBehavior]    min_wait = 5000    max_wait = 9000

经过 FunTester 地球分社群友指正,这里使用了FastHttpUser代替原来的HttpUser,还有另外一个类似的框架FastAPI,经过测试,性能提升一倍。最终版本内容如下:

from locust.contrib.fasthttp import FastHttpUserfrom locust import HttpUser, TaskSet, taskclass UserBehavior(TaskSet):    @task(1)    def profile(self):        self.client.get("/m")class WebsiteUser(FastHttpUser):    tasks = [UserBehavior]    min_wait = 5000    max_wait = 9000

JMeter

本地Java SDK版本 1.8.0_281,运行方式采取了command方式。GUI是在太坑了。

由于 JMeter 不用脚本,是在没啥好分享了,一切默认,配置协议、地址、端口、接口路径即可。

配置文件内容:

 <stringProp name="HTTPSampler.domain">192.168.80.169</stringProp>          <stringProp name="HTTPSampler.port">12345</stringProp>          <stringProp name="HTTPSampler.protocol">http</stringProp>          <stringProp name="HTTPSampler.contentEncoding"></stringProp>          <stringProp name="HTTPSampler.path">/m</stringProp>          <stringProp name="HTTPSampler.method">GET</stringProp>          <boolProp name="HTTPSampler.follow_redirects">true</boolProp>          <boolProp name="HTTPSampler.auto_redirects">false</boolProp>          <boolProp name="HTTPSampler.use_keepalive">true</boolProp>          <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>          <stringProp name="HTTPSampler.embedded_url_re"></stringProp>          <stringProp name="HTTPSampler.connect_timeout"></stringProp>          <stringProp name="HTTPSampler.response_timeout"></stringProp>

虽然 k6 是用golang写的,但是测试脚本语言是JavaScript,内容如下:

import http from 'k6/http';import { sleep } from 'k6';export default function() {  http.get('http://192.168.80.169:12345/m');}

FunTester

本机Java SDK版本同上,Groovy SDK版本:Groovy Version: 3.0.8 JVMJava堆内存设置 1G,其他参数默认。

本次默认使用看Groovy测试脚本的方式,运行方式也是Groovy脚本运行方式,是的,还有可以通过Java方式运行,优点就是控制设置JVM参数,实测影响不大。这个方式后期会在阿里开源**龙井(Alibaba Dragonwell)**时候会对比测试一下结果。

下面是脚本内容:

import com.funtester.config.Constantimport com.funtester.frame.execute.Concurrentimport com.funtester.frame.thread.RequestThreadTimesimport com.funtester.httpclient.ClientManageimport com.funtester.httpclient.FunLibraryimport com.funtester.utils.ArgsUtilimport org.apache.http.client.methods.HttpGetclass Share extends FunLibrary{    public static void main(String[] args) {        ClientManage.init(10, 5, 0, EMPTY, 0);        def util = new ArgsUtil(args)        int thread = util.getIntOrdefault(0,200);        int times = util.getIntOrdefault(1,10000);        String url = "http://192.168.80.169:12345/m";        HttpGet get = getHttpGet(url);        Constant.RUNUP_TIME = 0;        RequestThreadTimes task = new RequestThreadTimes(get, times);        new Concurrent(task, thread, "本地固定QPS测试").start();        testOver();    }}

万事俱备,准备测试!!!

我查资料的时候,很多直接从100线程并发开始,以倍增甚至质数增长到上万的,但在实际使用中单机根本用不到,我本机测试性能拐点大概 150 左右,最终瓶颈点也在 200 以内。所以呢,我设置了四项1050100200

首先 10 线程肯定都是轻轻松松的,硬件资源都是足够的,可以做一个参照。50 线程算是一个中等压力,主要对比 10 线程,100 线程差不多性能已经比较高了,但是应该还没到拐点,200 线程应该是超过拐点,到达瓶颈点。

当然这里有照顾locust的因素,经过我前期初测,实在没必要搞多节点的必要。

测试结果:

JMeterFunTester内存都比较高,这个特点一直存在。实测结果中,k6FunTester所测QPS比较高,也比较接近,JMeterlocust基本砍半,补充测试JMeter GUI测试结果更惨,还得砍。CPU数据除了locust以外其他都差不多,因为这个数据是我肉眼 记录感觉平均,实际测试过程中波动也比较大,误差是难免的。

盲猜locust应该是花费了一些精力同步计算测试结果了。而JMeter我是先测试后查看结果,应该排除了这个问题。

测到这里,locust基本要被淘汰了,实在有点低,消耗 CPU 还多,不过还是下一轮还是测了locust

测试结果:

结论跟上一轮差不多,具体的各位可以看看数据。

整个测试过程中JMeter数据中 QPS 波动过于大了,最低的不到2000,上面是 QPS 最高的一次。而且我发现JMeter对于端口或者连接利用率不是很好,QPS 一高起来,一会就报连接异常,网上一查说是端口不够用了,改完就好,继续增大线程,继续垮掉。可能是我姿势不太对,反正 FunTester 足够用。

经过查证,JMeter端口数大概使用了线程数三倍再多一点的端口数。FunTester用了两倍多一点,k6一直比较稳定的低,一直在 50 以内。这一点我以后得研究研究继续优化。

接下来的测试我抛弃locust,也抛弃JMeter了,错误率太高了,测试过程中,JMeter 测试用例可读性差的问题,显露无疑。

100 线程

只剩下两个强者,测试结果:

数据相差并不大,K6 消耗的 CPU 也逐渐降下来了,与 FunTester 很接近了,说明此时差不多应该是到了性能拐点附近。

200 线程

测试结果:

这里可以看出K6的优势还是非常明显的。初步判断应该到了瓶颈点,线程数增加了一倍,QPS 只增加了 10%量级,而且响应时间明显升高。

后来我通过修改JVM启动参数,增加堆内存,实际效果上没有明显提升。不得不说,golang协程非常厉害,Java协程这块有一个阿里龙井的解决方案,开源免费,我暂时没有测试,有兴趣的可以了解一下,真的相当牛逼。

今天的对比测试结束了,有兴趣的同学可以到 FunTester 地球分社中多多交流。

Have Fun, Tester!


FunTester腾讯云年度作者Boss直聘签约作者GDevOps官方合作媒体,非著名测试开发,欢迎关注。




About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK