关于物联网:JMeter-扩展开发BeanShell-数据模拟实现及性能探讨

42次阅读

共计 4730 个字符,预计需要花费 12 分钟才能阅读完成。

在写 JMeter 脚本的时候常常须要模仿一些数据,通常的做法是采纳”CSV Data Set Config”从 CSV 文件中读取数据。然而应用数据文件不够灵便,须要提前依据虚构用户数筹备相应数量的测试数据。比方,某利用的用户注册过程须要提供手机号码,如果采纳 CSV 文件,测试 1000 虚构用户就须要筹备 1000 个手机号码。如果测试过程中要减少虚构用户数目,则须要筹备更多的测试数据。整个过程比拟费时费力。

除了数据文件这种办法,对某些非凡的有法则的测试数据,咱们也能够采纳动静生成测试数据的形式,比方利用本文介绍的 BeanShell。

BeanShell 实现

咱们依然采纳上述手机号码的需要。用户注册过程中须要提供手机号码,测试场景中除了用户注册之外,不会对手机号码产生实际操作行为(比方发送短信等),只须要合乎数据库中表的定义即可(数据库中定义为 11 位 char 类型)。

实现过程须要思考不同的虚构用户在运行的时候不能应用雷同的手机号码,另外还须要思考同一个虚构用户在屡次循环执行的状况下也不能应用雷同的号码,否则无奈注册胜利。为了实现上述需要,咱们须要有一个标识虚构用户的 ID,以及在屡次循环执行的状况下标识的以后循环次数的值。

标识虚构用户能够通过 JMeter 的内置函数 __threadNum 来失去,而后者能够通过 JMeter 提供的计数器来实现,先来看一下咱们的脚本的构造。“HTTP 申请”须要应用手机号码发动一个测试申请,该手机号码是从一个名为 mobile 的 JMeter 变量中获得的,而该变量是通过“BeanShell 预处理程序”解决之后保留为 JMeter 的变量。

BeanShell 的实现,具体请看上面的代码。

import java.text.DecimalFormat;

String strThreadNum = "${__threadNum}"; // 获得以后的虚构用户 ID
int thNum = Integer.parseInt(strThreadNum);

String str = "${iterNo}"; // 获得该虚构用户以后的循环次数, iterNo 变量在计数器中定义
int i = Integer.parseInt(str);

int mobileNumLastFive = thNum * 10000 + i;
DecimalFormat df = new DecimalFormat("0000000000");
String fullNum = 4 + df.format(mobileNumLastFive); // 格式化成 4 结尾的 11 位手机号码
System.out.println(fullNum);

vars.put("mobile", fullNum); // 将手机号码存入名为 mobile 的变量,该变量能够在“HTTP 申请”中用到 

计数器的设置如下图所示,其中的援用名称就是在 BeanShell 里援用的 iterNo 变量。

BeanShell 和 Java 扩大性能比照

为了实现 JMeter 不反对的性能,之前的博客中咱们介绍了通过扩大 JMeter 函数相干的 Java 接口实现开发的形式,本文介绍的 BeanShell 脚本是另一种形式。接下来将比拟两种不同实现形式对 JMeter 的性能影响。咱们将通过实现一个简略的性能来进行比拟,并对这两种不同的实现形式的应用场景提供举荐。

测试场景

假如测试脚本须要产生一个长度为 1024 的随机字符串,字符串产生后将其赋值给一个名为”data”的变量,供前面的取样器来应用,在本文中应用的是“Dummy Sampler”(装置及介绍参见上一篇博客),利用它在自定义申请内容和响应内容上的劣势。BeanShell 版的 JMeter 测试脚本构造如下:

BeanShell 形式

BeanShell 预处理程序中的代码如下,生成了随机字符串后将值赋值给变量“data”:

import java.security.SecureRandom;

char[] seeds = "abcdefghijklmnopqrstuvwxyz0123456789".toCharArray();
StringBuffer res = new StringBuffer();
SecureRandom random = new SecureRandom();
for (int i=0; i<1024; i++) {res.append(seeds[random.nextInt(seeds.length - 1)]);
}
vars.put("data", res.toString());
res = null;

Dummy Sampler 中的“Response Data”输入框中传入变量“data”,如下图所示:

JMeter 自定义函数形式

扩大 JMeter 函数的实现形式下,测试脚本的根本构造与 BeanShell 形式相似,可参见下图。不一样的中央是把“BeanShell 预处理程序”替换成了“用户参数”。

“用户参数”中退出一个变量,该变量的值是自定义扩大的一个函数的运行后果:${__MyRandomString()}。

该自定义函数 __MyRandomString 的实现代码如下所示,具体请参见上一篇博客来学习如何扩大自定义函数。

package com.emqx.xmeter.demo.functions;

import java.security.SecureRandom;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

import org.apache.jmeter.engine.util.CompoundVariable;
import org.apache.jmeter.functions.AbstractFunction;
import org.apache.jmeter.functions.InvalidVariableException;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.samplers.Sampler;

public class MyRandomString extends AbstractFunction {private static final List<String> desc = new LinkedList<String>();

    private static final String KEY = "__MyRandomString";

    private SecureRandom random = new SecureRandom();
    private static char[] seeds = "abcdefghijklmnopqrstuvwxyz0123456789".toCharArray();

    @Override
    public List<String> getArgumentDesc() {return desc;}

    @Override
    public String execute(SampleResult previousResult, Sampler currentSampler) throws InvalidVariableException {StringBuffer res = new StringBuffer();
        for (int i=0; i<1024; i++) {res.append(seeds[random.nextInt(seeds.length - 1)]);
        }
        return res.toString();}

    @Override
    public void setParameters(Collection<CompoundVariable> parameters) throws InvalidVariableException { }

    @Override
    public String getReferenceKey() {return KEY;}

}

测试配置

测试运行之前,将别离应用两种形式编辑的脚本的线程组的线程数都设置为 100,循环次数 100 次。

测试机器是申请的规范虚机:1)2 核 CPU*2 GB 内存 2)20 GB 硬盘 3)操作系统 CentOS 7,64 位 4)Java 版本是 Open JDK 8

JMeter 测试采纳非 UI 形式运行。

测试后果

BeanShell 形式的脚本执行完测试约用了 1 分 18 秒 左右,控制台打印出的测试后果如下。JMeter 过程 CPU 使用率为 137%,内存使用率为 14%

summary + 2802 in 00:00:23 = 120.6/s Avg: 276 Min: 50 Max: 516 Err: 0 (0.00%) Active: 100 Started: 100 Finished: 0
summary + 4138 in 00:00:30 = 138.1/s Avg: 275 Min: 50 Max: 506 Err: 0 (0.00%) Active: 100 Started: 100 Finished: 0
summary = 6940 in 00:00:53 = 130.5/s Avg: 275 Min: 50 Max: 516 Err: 0 (0.00%)
summary + 3060 in 00:00:24 = 125.9/s Avg: 276 Min: 50 Max: 502 Err: 0 (0.00%) Active: 0 Started: 100 Finished: 100
summary = 10000 in 00:01:18 = 129.0/s Avg: 276 Min: 50 Max: 516 Err: 0 (0.00%)

Java 扩大 JMeter 函数的形式执行完测试约用了 32 秒 ,控制台打印出的测试后果如下。JMeter 过程 CPU 使用率为 50%,内存使用率为 5%。

summary + 6544 in 00:00:19 = 348.5/s Avg: 273 Min: 50 Max: 501 Err: 0 (0.00%) Active: 100 Started: 100 Finished: 0
summary + 3456 in 00:00:14 = 252.6/s Avg: 277 Min: 50 Max: 501 Err: 0 (0.00%) Active: 0 Started: 100 Finished: 100
summary = 10000 in 00:00:32 = 308.1/s Avg: 274 Min: 50 Max: 501 Err: 0 (0.00%)

由测试后果能够看到 Java 扩大 JMeter 函数的形式下执行工夫、CPU、内存占用率与 BeanShell 形式相比,占显著的劣势。大家须要留神的是 Avg、Min 和 Max 指的是“Dummy Sampler”的统计数据,两种应用形式下 Dummy Sampler 的执行工夫是统一的,而吞吐量后者比前者多了将近 1 倍,起因就在于测试步骤中的申请数据生成的不同实现形式下,后者比前者快了很多。

应用倡议

BeanShell 是 JMeter 内置的性能,然而因为它是脚本语言,动静加载执行的,因而效率不是很高,不太实用于频繁执行的场景,例如将 BeanShell 放在循环外部,一直被执行的场景。比拟适宜的利用场景是放在只执行一次、或者少数几次的中央,比方在循环内部读取配置文件内容等。

而 Java 扩大 JMeter 的实现形式运行效率比拟高,适宜于放在常常执行的测试步骤中。然而因为它不是 JMeter 内置的性能,扩大起来有肯定的工作量,而且部署的时候也有额定的开销(分布式运行的时候须要将自定义的 JAR 拷贝至所有的机器上)。大家能够依据本人的应用场景来抉择适宜的形式。

版权申明:本文为 EMQ 原创,转载请注明出处。

原文链接:https://www.emqx.com/zh/blog/jmeter-extension-development-beanshell-data-simulation

正文完
 0