性能测试工具 基于 Jmeter 的轻量级云压测平台的原理与实现 (二):压测引擎

zyanycall · December 13, 2018 · Last by 惜木 replied at March 06, 2020 · 6673 hits

希望能帮我点上一颗star,多谢。
感谢大家对平台的使用和支持,希望大家多提issue,多和我讨论。

github:[https://github.com/zyanycall/stressTestPlatform]

平台的技术

平台的初衷

平台的核心初衷很简单,就是能在浏览器中完成一系列Jmeter操作,包括启停脚本,在线监控,在线报告。
但是想一下,其实Jmeter的核心初衷貌似更简单:“load test functional behavior and measure performance”,大意是能进行性能测试并且查看监控结果。
结果Jmeter的代码量突破了67万行。
平台中我的代码突破了8000行。
稍微感慨啊,我本来合计“小而美”搞定的,看来初衷和代码行数真的不成正比。

平台从开源开始到现在拥有了一些核心的功能:

  • 启动脚本,包括Jmeter-API的启动和调用Jmeter-Home的拼装脚本启动,包括单机节点启动和分布式启动。
  • 全部停止脚本和单独停止脚本,单机和分布式情况下都适用。
  • 支持平台内适用Jmeter-API的方式同时启动多脚本,同时监控的数据是正确的。
  • Jmeter-API启动脚本时,支持Jmeter自带的函数,同时支持更多的Jmeter的常用sampler。
  • 支持Jmeter-API方式的脚本调试,在线也能看脚本的效果和问题。
  • 参数化文件支持自动同步到各个节点机。
  • 性能/调试报告的异步生成及下载。
  • 系统空间的控制,支持不生成测试报告和保留报告而仅删除测试结果数据。

印象深刻的技术点:

  • shiro的配置及权限控制。
  • spring-boot读取配置文件及Controller——Service——DAO——Mapper的各种操作。
  • 子类的方式重写Jmeter的源码方法。
  • javassist字节码修改方式重写Jmeter源码。
  • 观察者模式重写Jmeter调用脚本的各种监听器。
  • classLoader的实际运用和static代码块。
  • Java内调用命令行和各种回调。
  • 异步线程池方式实现xsl模板生成html报告。
  • 文件上传下载。
  • 前端监控的定时触发,数据在内存中如何对压测机性能影响最小,内存和数据库。
  • 前端监控的数据如何计算得到,尤其是分布式这些数据要怎么处理。
  • Echarts的写法和调试。
  • 数据库表的设计,配置项的设计。

然后我发现自己面对所有这些技术问题,解决的速度是很快的,我觉得自己是战无不胜的。

issue中提的一个问题我印象很深刻,是说为什么我的平台执行不了Jmeter自带函数?
为此我打了几十个断点来追查问题,最终确认了是动态的系统变量少了东西。
印象深刻一是因为源码查的真的很深入,看过源码的会了解,Jmeter对jmx树的解析相当复杂,能有几十个各种实现类,断点很不好打。二是我真的一度放弃过,当然最终坚持下来并很快解决了。

然后可惜,代码还是来到了8000行,我的“小而美”去哪里了。

为什么执着于Jmeter-API

就一压测任务,你直接调用Jmeter脚本执行就好了啊,也有测试报告查看,也支持分布式压测啊。
原因其实不复杂:Jmeter-API最开始支持那就一直维护下去了,这种方式支持的功能多很多,同时grafana的监控不太理想。

而监控的数据只能来自Jmeter-API。

平台能带来什么

任何想通过Jmeter-API来调用jmx脚本的项目,其实都可以借鉴一下我的代码。
确实Jmeter的源码已经够可以了,但是当前Jmeter-API还是不太方便。

压测引擎

从我上面的功能代码介绍也能看到,最核心最费劲的就是压测引擎了,同时目前这部分实现算比较稳定的。
所以我打算先从最核心的开始。

我会先介绍整体,然后通过介绍各个重点需求的实现方式来逐步讲解代码。

前端入口

$.ajax({
type: "POST",
url: baseURL + "test/stressFile/runOnce",
contentType: "application/json",
data: JSON.stringify(numberToArray(fileIds)),
success: function (r) {
if (r.code == 0) {
vm.reload();
}
alert(r.msg, function () {
});
}
});

Controller

@SysLog("立即执行性能测试用例脚本文件")
@RequestMapping("/runOnce")
@RequiresPermissions("test:stress:runOnce")
public R run(@RequestBody Long[] fileIds) {
return R.ok(stressTestFileService.run(fileIds));
}

必要的Jmeter配置准备

本来想精简一下的,其实这部分Jmeter源码中写的比较复杂,因为Jmeter的功能更多,这些都是自己抽出来是最简单可用的。
解释一下,代码简单就是说读取了几个配置文件,jmeter.properties,user.properties,system.properties,将其中的配置项汇总一下。
设置一下的本地的Locale环境。
其实到这里,是可以仅将这3个配置文件抽离出来,即不需要整个Jmeter的home目录,仅要这3个配置文件就能运行Jmeter脚本。
甚至仅在代码中写要的配置,都不需要实体的配置文件即可。

当然随着功能越来越多,平台跟Jmeter的耦合也越来越多,这个Jmeter_home目录还是越来越必要了。
主要是为了异步的生成测试报告,Jmeter自带函数的一些必要的加载,
当然要完全去掉Jmeter_home目录的耦合也完全可行,但这会无形之中提高不少维护成本,不太合适。

String jmeterHomeBin = getJmeterHomeBin();
JMeterUtils.loadJMeterProperties(jmeterHomeBin + File.separator + "jmeter.properties");
JMeterUtils.setJMeterHome(getJmeterHome());
JMeterUtils.initLocale();

Properties jmeterProps = JMeterUtils.getJMeterProperties();

// Add local JMeter properties, if the file is found
String userProp = JMeterUtils.getPropDefault("user.properties", ""); //$NON-NLS-1$
if (userProp.length() > 0) { //$NON-NLS-1$
File file = JMeterUtils.findFile(userProp);
if (file.canRead()) {
try (FileInputStream fis = new FileInputStream(file)) {
Properties tmp = new Properties();
tmp.load(fis);
jmeterProps.putAll(tmp);
} catch (IOException e) {
}
}
}

// Add local system properties, if the file is found
String sysProp = JMeterUtils.getPropDefault("system.properties", ""); //$NON-NLS-1$
if (sysProp.length() > 0) {
File file = JMeterUtils.findFile(sysProp);
if (file.canRead()) {
try (FileInputStream fis = new FileInputStream(file)) {
System.getProperties().load(fis);
} catch (IOException e) {
}
}
}

jmeterProps.put("jmeter.version", JMeterUtils.getJMeterVersion());

对Jmeter脚本的必要加载操作

FileServer.getFileServer().setBaseForScript(jmxFile);

设置jmx脚本文件的工作目录,主要是可以根据这个来找到参数化文件及实现其文件流。

HashTree jmxTree = SaveService.loadTree(jmxFile);

加载jmx脚本,本身这个操作非常复杂。
jmx脚本中通常会包含参数化文件,用户自定义的参数化,Jmeter自定义函数,各种Sampler的实现,断言,甚至用户自定义的插件等等。
同时还有各种监听接口的初始化。
这些都是要找到实现类加载的,源码中包含非常多的实现类。

JMeter.convertSubTree(jmxTree);

去掉没用的节点元素,替换掉可以替换的控制器。
这个是递归实现的,本身这个方法我也没动过,看着就复杂。

单机执行脚本

JMeterEngine engine = new StandardJMeterEngine();
engine.configure(jmxTree);
engine.runTest();

初始化默认的压测引擎,分布式的压测引擎其实也是使用的这个。
configure方法是设置回调的监听器,并添加状态。
runTest就太复杂了,简单说几点吧:

  1. 设置各种监听器和配置准备,比如活动的用户数量的统计就会来自这里。
  2. 启动是按照threadgroup来的,按组启动的,脚本内众多相似的线程同属一个组。
  3. 设置的启动间隔时间,比如1秒内启动100个,这种的处理。
  4. 启动之前还要有一个GC。(这对多脚本的同时进行有影响呀)
  5. 开始和停止之后都要通知各个监听器。
  6. 单个thread执行时遇到的断言判断,执行间隔,函数实现等。

其实这里我看的也不是很深入,复杂是一方面,代码其实注释也少,加的东西也太多了。
同时这里比较稳定(Jmeter的核心不能不稳定)。

分布式执行脚本

java.util.StringTokenizer st = new java.util.StringTokenizer(slaveStr, ",");//$NON-NLS-1$
List<String> hosts = new LinkedList<>();
while (st.hasMoreElements()) {
hosts.add((String) st.nextElement());
}
DistributedRunner distributedRunner = new DistributedRunner();
distributedRunner.setStdout(System.out); // NOSONAR
distributedRunner.setStdErr(System.err); // NOSONAR
distributedRunner.init(hosts, jmxTree);
engines.addAll(distributedRunner.getEngines());
distributedRunner.start();

StringTokenizer是为了初始化hosts参数使用的,直接搬过来也没改。
DistributedRunner本质上还是StandardJMeterEngine来执行的压测,使用的是rmi的协议实现的分布式压测。
执行不多说了,还增加了输出流和错误流。

最后

至此就会简单的执行Jmeter的jmx文件,当然我的代码中会包含各种其他的监听器,static代码块,抛弃了Jmeter的classloader,甚至还改了Jmeter的Runner代码。
这些主要是为了监听数据,加载Jmeter自带函数,可以同时进行多个jmx脚本,动态修改Jmeter配置文件等功能服务的。

共收到 78 条回复 时间 点赞
蓝蓝 有咋开源的压测服务化平台项目吗? 中提及了此贴 12 Feb 09:32

想问一下楼主 在上传jmx后启动 提示 异常请联系管理员,可否看出是不是环境问题,提示:
Problem loading XML from:'D:\Wanglei\apache-jmeter\apache-jmeter-4.0\Performence\20190213215933351\case20190213215933768.jmx', missing class com.thoughtworks.xstream.converters.ConversionException:

回复

你本地的JMeter装了插件,服务器上没装,解析jmx报错

我刚开始也想到了,但是我只用到了普通线程组,http请求取样器 和header管理 还有查看结果树,TPS,ResponseTime图 而且编写脚本的jmeter和执行的jmeter都是本地的同一个文件 应该不会有插件问题

回复

arrow 回复

把。TPS 和 Responsetime ,查看结果树 删掉后 确实成功了。。

回复

查看结果树应该没问题,主要是另外两个监听属于插件,删掉就可以了。
平台自带监听,比jp@gc 的监听要和谐一些(自认为功能也好了不少😁 )。

zyanycall 回复

哈哈 非常感谢,因为我司重要项目压测的时候 一般申请8-10台(因为不太懂所以只能多加压测机器。。) 8c16g, 这样的机器运行一个 slave 太浪费了。所以单个ip 不同端口 部署多个slave 机器 在试用的时候发现StressTestSlaveService 添加的时候 ip不能重复,仔细查看发现test_stress_slave表设置了IP 为索引。于是把索引删了。。。保存成功 但是因为今天下午刚本地部署成功,还没来得及看代码(虽然也看不懂。。)不知道删掉这个索引 会不会触发其他问题

回复

没影响。
负载机是高CPU消耗的应用,除非机器CPU核心特别多如32核及以上,可以使用多进程,像你的8C16G的单进程就可以了,是没必要搞单IP多端口的多个slave进程的。
当然你们可以多尝试尝试。

已Star,期待楼主后续的分享(话说有没联系方式,加个微信聊一聊)
建议做成一个docker镜像吧,方便点

zyanycall 回复

关于jmeter也不是太懂。但是最多的时候一个master不做压力机,后面有15个左右的slave,但是我来做一般每个slave最多500线程,然后看到网上有说每个slave不要超过200个线程,100个最佳,所以也不太清楚到底多少合适,之前用的8c16g 开3个进程 每个进程300线程左右,观察slave机器 CPU只有在启动的时候会暴增,之后会平稳,内存使用也基本在12g以内。但是关于楼主说的负载机是搞CPU消耗的应用,这个在我这边用的有点奇怪,有时候做压测CPU使用会比较高,有的时间就比较低,不知道是为什么,😨
同时问一个问题,楼主的压测平台是避免了 负载机过多导致控制机性能不够用的场景么,但是看楼主分布式节点启动的还是jmeter-server 问一下master机器是平台的系统配置的本地绝对路径的Jmeter_HOME么

感觉楼主对jmeter 研究挺深的,希望以后有兴趣可以出一个单机Jmeter调优,和分布式master&&slave调优,比如内存堆栈大小,GC值等

回复

高CPU消耗是说slave负载机的瓶颈一般是CPU,或者网络带宽。
master可以是Jmeter_HOME 也可以是 服务器进程,两者可以选择,可以配置。
我的平台主要是让Jmeter的单机或者分布式更方便使用,目前并不会提高性能。

Jmeter无论单机还是slave就是一个Java进程,按照调优JVM的方式调优就好了。

大佬,请问一下,如果我想部署到阿里云服务器的话,需要什么准备工作,看到你都是本地部署这样子的,放到云服务器还得指导一二啊。。。。还有,需要上传那个几十mb的jmeter包做依赖吗,谢谢~阿里嘎多~

zyanycall #16 · March 20, 2019 作者
测试初妹 回复

云服务器和本地服务器很类似吧。建议你本地搭完环境之后和你们运维合作,搭建阿里云服务器。
因为涉及服务器的开销价钱,用户权限,端口权限,磁盘文件大小等等。

zyanycall 回复

emmm,感谢那么神速的回复,其实我有一个学生版本的阿里云了,钱已经不是问题,啊哈啊哈~

学生党阿里云各位了解一下。

测试场景组装 是要实现什么功能

zyanycall #19 · April 08, 2019 作者
suda23 回复

这个功能已经废弃。后续都删掉。

目前在使用平台自身的定时任务时碰到了点问题,使用Jmeter-Home就正常了
如果完全使用Jmeter-Home来运行是否可行,
比如在生成报告的同时,是否还能继续下一个压测任务

之前好像看到书记您说过不用jmeter5的原因,但忘了在哪看到了,能再解释一下不升级到jmeter5的原因吗
每次拜读一、二的原文和评论都有些新的收获,再次感谢达康书记😁 希望还有第三篇

zyanycall #21 · April 15, 2019 作者
suda23 回复

你好,感谢对平台的肯定。
定时任务这块如果是要结合web平台来做,肯定是需要代码量的,这部分我还没开发。如果是基于Jmeter的,那么使用Jmeter-Home应该是可以的(这你也试过了可以,感谢),因为使用Jmeter-Home的原理就是执行Jmx脚本,和使用源生Jmeter是一样一样的。

放弃Jmeter5是因为我当初在测试的时候,发现Jmeter 5 对参数化文件支持的不好,具体我也忘记了,我们就是普通的使用回车换行的参数化文件,但那天是遇到了问题一直报请求失败,当时还没有调试脚本的功能,追查了很久发现回退Jmeter版本就没问题了,所以就一直保留Jmeter4 的api方式,一直不升级。

以上是对你问题的一些回答吧,下面我扯点儿别的。

  1. 定时任务为啥一直不做呢,因为我觉得定时任务总有一些弊端和不太实用的。 性能测试是一个严肃的事情,说每时每刻都需要人盯着都不为过,那么有了定时任务让其自动执行是不太安全的。可能你会说轻量级的相当于回归测试的压测需要定时执行,来检查系统的健康程度,我仍然认为这不是不盯着让它自动运行的理由,不够严肃,一旦出了问题得不偿失(比如各种脏数据问题内存的数据库的,给流量高峰添乱等等)。 说不太实用是因为除了定时任务,更需要的往往是钩子执行,如代码提交之后就进行性能测试,这样更有意义一些,就是说不仅仅时间是触发条件,其他操作也要成为性能测试的触发条件,结合起来才是最实用的。而这种开发量稍微大了些,稍微偏离了性能测试平台的主核心任务,这个需要集成更多的三方包来搞,或者说业内对这里已经有方案如Jenkins+Jmeter还是可以的。 同时Jmeter自己也有对定时任务的实现,简单的定时任务完全可以胜任,所以平台对这部分需求也不急迫。
  2. Jmeter 4 已经满足了我现在的所有需求,所以我是觉得没必要赶潮流硬上Jmeter 5,所以我也不升级。未来如果有场景非Jmeter 5不可,那我肯定会升级的。
zyanycall 回复

不知后续还有什么开发计划

我这边做了2个小改动,
1是对于线程组的在线修改,压测过程中,调整并发还挺频繁的,所以做了一个这个功能

2是对于参数文件支持指定salve进行同步,因为并发过程中多个savle用同一批数据的话,可能会出错

能搞成docker来部署就完美了。。。。

@suda23 同步master到slave 上面会对文件自动分割么,假如参数化的文件是一次性文件,每个slave上面的同一个文件内容肯定是不同的。不然会报错。

另外想问一下楼主更新成分布式的时候支持不同slave可以执行不同的线程数,可以设定一个单台slave最高启动线程数量,当总线程数大于单台的时候,就自动拉起另一个试压机,直到达到指定线程数量,压测调试的时候不是每次都要开启所有的压测机器,但是不同的系统又占用相同的压测资源。前一段时间我这边有1台16c32g+20台4c8g压测机。我的办法是通过Jenkins执行,构建器为1 新的压测任务让他自动排队,但是这样也会有资源浪费

zyanycall #26 · May 06, 2019 作者
回复

目前没做这么细。
每个slave执行的是相同的脚本,像线程数,步长等等都是一样的,本身Jmeter并没有master配置一个总的线程数,其他slave去平分这些线程数的概念(或者权重平分),都是master打算要执行一个脚本,其他slave都是按照这个来执行,这是两种压力设计,很明显你说的这种Jmeter本身就没有。
你说的这种其实要考虑的很多,比如一个脚本内配置了多个线程组,每个线程组的线程数都不一样,那你说的“直到达到指定线程数量”要做的就比较多了,比如要保持住每个线程组线程数的比例,要同步增加,或者说“指定线程数量”要细分化,即对每一个线程数都要有一个指定的线程数量,这样如果几个线程组还行,如果千百个线程组,你这要如何细分。这就是举个例子吧,意思是说实际要做的没有那么简单。
Jmeter这种压力设计是有它的考虑的,我也认为是最省事的。
平台目前不想颠覆Jmeter的理念,平台的核心目前还是保持住Jmeter的所有特性,是保持,不是另立门户。

明白,因为最近的项目客户请了TestIn的同行来做压测,看到他们封装的Jmeter平台支持在平台设置脚本线程数量,以及运行时间,保存请求失败结果等等,联想到之前多个压测机器用不到的时候会有资源浪费,他们的平台就会自动分配每个slave机器的线程数,至于“直到达到指定线程数量”楼主可能没理解,这个意思是假如每个压力机平台可设置最高启动1000线程,当我在平台设置总线程数量为7500的时候平台就可以算出需要8台压力机,具体是使用8台压力机平分7500这个数字(原生),还是控制7台压力机执行7000,一台执行500,平台可以在做研究那种方法比较好。同时楼主提到的多个线程组的控制,这个我没到没想到,因为jmeter整体是一个进程,每个线程组线程数的比例,jmeter原生本身会做控制,这个并不需要平台介入吧。不过确实TestIn同事的脚本所有的场景都放在了一个线程组下面,用控制器来隔离,很大很大。不知道是不是他们的平台也碰到了楼主说的线程组线程分配的问题。

zyanycall #28 · May 06, 2019 作者
回复

“每个线程组线程数的比例,jmeter原生本身会做控制,这个并不需要平台介入吧”,据我了解,Jmeter本身控制不了比例,能控制的仅是数量。平台需要根据比例计算出数量,传给Jmeter让其执行。
这种解决办法也有吧,一个线程组一个脚本,多个脚本同时执行达到多个线程组同时进行的效果,这也是可以的,可以避开问题,曲线救国吧。

我这边因为资源有限,所以简单做了一个jmeter和Jenkins的集成,主要依靠shell脚本。
在Jenkins构建的时候设置脚本启动的线程数量,并通过变量传到构建的shell脚本里,shell脚本是启动jmeter的命令通过全局变量把脚本运行时间和线程数量传输到脚本里面。把生成的日志&&html报告等等指定在工程在Jenkins里对应的工作空间中,

可直接查看

zyanycall #30 · May 06, 2019 作者
回复

赞,做的还是不错的。

所以我就是每个场景放一个线程组,不然没办法控制线程比例,但是我认为这样已经可以了,在深就是jmeter的底层原理了,不太明白什么时候需要控制每个线程组的线程数量比例,原生只能控制线程组的数量,但是这样已经够了吧。针对每个场景不同的每个接口线程比例可能不同的话, 原生有很多控制器可以做到对单个线程组内线程进行比例控制吧,如果提升一级到控制不同线程组来达到不同场景的需求。原生应该做不到。原来的设计思想可能是每个线程组可满足一个场景即可,测试人员只需要控制线程组的线程数量,用控制器来分配线程即可。
楼主说的“平台需要根据比例计算出数量,传给Jmeter让其执行”我理解平台可以做到算出线程组的线程数量就OK了,简单看一下jmeter的启动日志会发现线程是根据线程组来启动的,线程的分配应该是按照脚本的执行顺序或者控制器来实施。平台介入的话应该会对原生的逻辑进行改动。

说的可能有点乱。但是总体意思就是平台只需做到可以控制线程组的线程启动数量即可。甚至平台用 总线程数/单个slave最大启动线程数量,结果舍去小数点并+1,然后用总线程数/前面的结果即可。这样也不用更改jmeter原生的线程控制。
举个例子:
单个slave最高启动1000线程,需求7500并发
平台:7500/1000=7.5 舍去小数点并+1=8,7500/8=938(四舍五入得整数)得出每个slave需启动938个线程即可,所有的slave线程数一致。无需更改原生的逻辑

Jenkins挺方便的,同时利用shell脚本写了一些启动停止和重启jmeter-sever的脚本,利用Jenkins触发。

还有手工把文件分割成指定份数,并用脚本传不同文件到不同服务器并把名字改成一致,或者把相同的参数化的文件发送到slave机器上

感觉这些都可以在平台上面实现呢。如果可以做到,对我们这样的平民测试简直如有神助啊。

其实例如阿里的PTS,腾讯的压测大师,美团的什么锤。大型的互联网公司都会有一些自己的封装一些压测平台的,最近在找比较方便的压测平台,感觉开源的就楼主的最好了。。
希望楼主可以持续更新。或者改成收费也行。

zyanycall 回复

楼主,感觉你的执行方法没有调对,我的服务器也装了插件,使用了stepping thread groups线程组,本地可以执行,用平台就报错,无法识别到这个类。

zyanycall #35 · May 31, 2019 作者
磨牙君 回复

插件自己加到环境里。

我把内核换成5.1.1生成报告的时候会报空指针

Author only

你好我问一下,脚本管理上传怎么不好用啊,后台没反应

zyanycall #39 · June 03, 2019 作者
kexinqw 回复

5.1.1目前支持的不好,我都是用的4.0的。

zyanycall #40 · June 03, 2019 作者
磨牙君 回复

插件需要加载平台的JVM环境中。这个需要自己手动加载,如在IDE中引用三方jar包,pom文件制定插件所在的目录等。

zyanycall #41 · June 03, 2019 作者
zmsky8888 回复

可以debug一下看看问题在哪里。详细的可以提一个issue。

Author only


再次执行就报这个错

zyanycall #44 · June 03, 2019 作者
zmsky8888 回复

正常JVM环境中是有这个类的。你用的Jmeter是5.1.1吗。

Author only
zyanycall #46 · June 03, 2019 作者
zmsky8888 回复


是有这个类的。

Author only

楼主你这个可以支持集群发压吗

zyanycall #49 · July 02, 2019 作者
zmsky8888 回复

支持

Author only

没看到怎么集群发压呢?在前段页面启动,只调用一台机器

zyanycall #52 · July 27, 2019 作者
trygood 回复

集群的控制是Jmeter自带的,你如果看Jmeter源码就知道了。
平台只是调用Jmeter的API,如果配置了集群就会使用集群。

嗯 奇怪的是4.0的jmeter没有totaltps这个类。。。

jmeter的集群是这样的吗?脚本有100个线程,集群中有两个压力机,那么实际线上是200?

zyanycall #55 · July 29, 2019 作者
trygood 回复

是的。
但是目前平台支持压力机压力负载配置,比如可以把两个压力机承担的都是原脚本压力的 50% ,这样加起来就是 100 了。
可以调大或者调小压力。
源生的Jmeter的分布式节点机的坑还是不少的,建议压测前重启。

zyanycall 回复

但是在报告中怎么看到的还是100线程呢?是html的报告有问题吗?
这个感觉不是很明确啊,比如:一个master调度两台slave,脚本设置100线程,到底是100还是200线程呢

将jmeter集成平台最大的问题是依赖包要解决,LZ选择拼装的模式,也是OK的,但不是最佳的

回复

完全这样实现,不仅仅是平分总线程数,还可以针对每个agent压力机进行比例分配和线程数分配。这种并不难,还有更深入的,压测执行过程可以动态增减线程数(细化到单台压力机)

分布式压测为什么不能生成调试报告?平台中分布式节点上执行不会自动停止,而且没有报告生成

分布式节点运行脚本报错

trygood 回复

建议你仔细了解一下Jmeter的自有的压力分布的实现。平台对Jmeter的压力分布实现原理配置等没有做任何修改,做的仅是优化。
节点机的压力负载调节也是在改动原jmx文件在内存中对象的方式来实现的。

ranran 回复

你这个报错是Jmeter自己报的,建议查一下配置。
之前我也说过,Jmeter对分布式节点slave的管理很弱,这是源生的弊端。不过正常都会自动停止的。分布式停不下来建议直接重启节点没关系的。
调试报告仅仅是调试,我还没想分布式那么远,有点儿太复杂了。

怎么使用standerpluning提供的线程组?api方式可以运行吗

trygood 回复

我没看懂你的问题。

如果想升级插件,或者趴其他第三方远的插件;放进项目如何操作

直接改源码吧,改maven引用。

有交流群吗,拉个群一起交流下可以吗

我在考虑另外一种做法,不用现有的jmeter-server(没找到办法解决master和agent不在一个网络的情况),像jenkins一样,在每个agent上启动一个server,负责 接收执行请求,下载脚本和数据,本地方式启动jemter,上传jtl文件到master,master合并jtl,生成报告,正在琢磨这样合并jtl会不会有问题

bessway 回复

这种思路很好,总的来说就是不要每次请求都要传数据,而是说slave先保存数据,测试结束之后走文件传输,例如scp把文件数据交给master整合。
其实这种方式我尝试过:

  1. Jmeter自带diskstore存储模式,就会将请求结果保存在本地文件。但是这种方式不行,文件保存路径是默认的在/tmp下,文件名是随机的如SerialisedSampleSender383066585222874452.ser 并没有地方能指定这个文件是哪个脚本文件的,这个文件名的前缀后缀是Jmeter定义的,但是中间的数字是JDK的方法File.createTempFile("SerialisedSampleSender", ".ser"); 定义的。生成的ser 文件,格式内容是xml 的,文件比较大,同时默认是如果进程退出则文件删除,要不然也不会在tmp里,同时文件有分割,大概113M左右,就会被分割成一个子文件。
  2. 如果是自己实现,slave存储jtl或者csv文件,来传输给master再拼在一起,这种我试过,在某些字段如99%,90%这些,和Jmeter实时传输汇总的得到的测试报告不同,也就是说自己拼装的 和 Jmeter源生的方式,得到的测试报告不一样,而Jmeter源生的测试报告业界更承认。 当然这种误差很小,不敏感的可以接受。

444104595@qq.com
qq:97891996

大佬 我发现了一个bug,发邮件给你了。你查收下邮件啊 发到这个邮箱了 zyanycall@gmail.com

会飞的猪 回复

收到邮件了,问题我还没有复现(工作ing)。
希望把问题提到issue上去,这样比较方便追踪(gmail 国内上稍微费劲)。
初步的直觉的判断,我觉得不太可能,因为纯粹是源生的Jmeter来驱动运行的,不太应该。但是你提到了吞吐率控制器,可能另有玄机。

zyanycall 回复

好的 我一会儿提到issue上 刚才提到的吞吐率控制器是这个 Constant Throughput Timer

最近用樓主開源的測試平臺,jmeter更新到5.2.1, 單機生成報告沒什麽問題

ryhnatwoods 回复

2020年来了,都5.2.1版本了🤔

分布式执行时需要个问题。 调用slave机器时,如果模式
MASTER_JMETER_USE_SCRIPT_KEY 为false,即在服务器进程内启动Jmeter压测 则会报下面的错误。但是选择true,使用jmeter原生的,则无错误。 缺失的rmi_keystore.jks 我是应该生成后放在哪儿呢?。目前slave机器已经把ssl关闭了

Set this if you don't want to use SSL for RMI

server.rmi.ssl.disable=true

报错信息
2020-01-23 14:34:42.396 DEBUG 23260 --- [nio-8080-exec-9] i.r.m.t.d.StressTestSlaveDao.queryList : ==> Parameters: 1(Integer)
2020-01-23 14:34:42.397 DEBUG 23260 --- [nio-8080-exec-9] i.r.m.t.d.StressTestSlaveDao.queryList : <== Total: 2
2020-01-23 14:34:42.397 INFO 23260 --- [nio-8080-exec-9] o.a.jmeter.engine.DistributedRunner : Configuring remote engine: 172.21.141.50:1099
Configuring remote engine: 172.21.141.50:1099
2020-01-23 14:34:42.401 ERROR 23260 --- [nio-8080-exec-9] o.a.jmeter.engine.DistributedRunner : Failed to create engine at 172.21.141.50:1099

java.rmi.ConnectIOException: Exception creating connection to: 172.21.141.50; nested exception is:
java.io.FileNotFoundException: rmi_keystore.jks (No such file or directory)
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:631)
at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:216)
at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:202)
at sun.rmi.server.UnicastRef.newCall(UnicastRef.java:338)
at sun.rmi.registry.RegistryImpl_Stub.lookup(RegistryImpl_Stub.java:116)
at org.apache.jmeter.engine.ClientJMeterEngine.getEngine(ClientJMeterEngine.java:72)
at org.apache.jmeter.engine.ClientJMeterEngine.(ClientJMeterEngine.java:85)
at io.renren.modules.test.jmeter.runner.LocalDistributedRunner.createEngine(LocalDistributedRunner.java:284)
at io.renren.modules.test.jmeter.runner.LocalDistributedRunner.getClientEngine(LocalDistributedRunner.java:260)
at io.renren.modules.test.jmeter.runner.LocalDistributedRunner.init(LocalDistributedRunner.java:140)
at io.renren.modules.test.service.impl.StressTestFileServiceImpl.excuteJmeterRunLocal(StressTestFileServiceImpl.java:574)
at io.renren.modules.test.service.impl.StressTestFileServiceImpl.runSingle(StressTestFileServiceImpl.java

小山 回复

Jmeter 默认master 和 slave 之间,是需要SSL通信的,即加密通信。但是这个可以关掉。
因为我们一般都是内网,不存在窃取请求内容等安全性问题,还有SSL加密解密的过程会带来性能损耗。
所以一般都是关闭的。具体关闭的方式,日志中已经提示:server.rmi.ssl.disable is set to 'true' 这个配置在master的jmeter.properties 文件中,slave中也有一个。 改成true即可。

zyanycall 回复

master和slave都已经设置为server.rmi.ssl.disable=true。 主要问题是
如果平台模式
MASTER_JMETER_USE_SCRIPT_KEY 为false,即在服务器进程内启动Jmeter压测 则会报下面的错误。但是选择true,平台使用jmeter原生的,则无错误。

看代码似乎MASTER_JMETER_USE_SCRIPT_KEY 为false 时,是自己实现的远端调用

想请教,我用来压测服务器上某个接口用的本地机器,对压测结果会有很大影响吗?目前,我用两台不同的本地机器,同样的jmeter配置参数,来压测服务器上的一个接口,发现压测结果差别很大,请问这样的话,岂不是压测结果和用来压测接口的本地机器配置有很大关系?

81Floor has been deleted
需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up