如果想要压测一些三方组件,比如MQ,redis什么的,jmeter本身是不支持的。
本文以开发一个压测netty的echo示例,说明如何自定义jmeter的sampler。
本文以idea示例,
jmeter的核心依赖:
<dependency>
<groupId>org.apache.jmetergroupId>
<artifactId>ApacheJMeter_coreartifactId>
<version>5.5version>
dependency>
<dependency>
<groupId>org.apache.jmetergroupId>
<artifactId>ApacheJMeter_javaartifactId>
<version>5.5version>
dependency>
三方依赖,比如我要压测netty,开发一个netty客户端,必然要引入netty相关的依赖:
<dependency>
<groupId>io.nettygroupId>
<artifactId>netty-handlerartifactId>
<version>${netty.version}version>
dependency>
<dependency>
<groupId>io.nettygroupId>
<artifactId>netty-transport-native-epollartifactId>
<version>${netty.version}version>
dependency>
这部分代码可以从netty的示例里[io.netty.example.echo.EchoClient]拿过来改改就行:
public class EchoClient {
static final int SIZE = Integer.parseInt(System.getProperty("size", "256"));
private Channel channel;
public EchoClient(String host, int port) {
EventLoopGroup group = new NioEventLoopGroup();
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.option(ChannelOption.SO_SNDBUF, 1024 * 1024)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast("flushHandler", new FlushConsolidationHandler(1024, true));
p.addLast(new EchoClientHandler());
}
});
// Start the client.
try {
channel = b.connect(host, port).sync().channel();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public void write(String message) {
channel.writeAndFlush(message);
}
}
@Slf4j
public class EchoTest extends AbstractJavaSamplerClient {
private String label = "echo";
private String host;
private int port;
private String content;
private AtomicInteger index = new AtomicInteger(0);
public static EchoClient client;
public EchoTest() {
log.info(this.whoAmI() + "\tConstruct");
}
@Override
public void setupTest(JavaSamplerContext context) {
// 读取设置的请求参数
this.setupValues(context);
// 注意如果client不是静态的类变量,在jmeter指定并发数的时候,每个线程会创建一个client对象,所以如果需要多少个客户端,根据自己场景调整
if (client == null) {
synchronized (EchoTest.class) {
if (client == null) {
client = new EchoClient(this.host, this.port);
}
}
}
}
@Override
public SampleResult runTest(JavaSamplerContext javaSamplerContext) {
SampleResult results = new SampleResult();
results.setSentBytes(content.length());
results.setDataType("text");
// 用来计算一个请求的耗时的
results.sampleStart();
try {
// 除了这行业务代码,其它可以算是模板范式
client.write(content);
results.setResponseOK();
results.setResponseCodeOK();
results.setSuccessful(true);
} finally {
results.sampleEnd();
}
results.setSampleLabel(this.label);
return results;
}
private void setupValues(JavaSamplerContext context) {
this.host = context.getParameter("Host");
this.port = context.getIntParameter("Port");
this.content = context.getParameter("Content");
}
/**
* 这个方法就是在Jmeter上设置的请求参数
*/
@Override
public Arguments getDefaultParameters() {
Arguments params = new Arguments();
params.addArgument("Host", "127.0.0.1");
params.addArgument("Port", "8007");
params.addArgument("Content", "输入内容");
return params;
}
private String whoAmI() {
return Thread.currentThread() + "@" + Integer.toHexString(this.hashCode());
}
}
关键地方已经加上注释了,其它场景可以照这个模板走就行。
因为有三方依赖,打包的时候需要把这些依赖也打包进行来,因此使用maven-assembly-plugin插件:
<build>
<finalName>${artifactId}finalName>
<plugins>
<plugin>
<artifactId>maven-assembly-pluginartifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependenciesdescriptorRef>
descriptorRefs>
configuration>
<executions>
<execution>
<id>make-assemblyid>
<phase>packagephase>
<goals>
<goal>singlegoal>
goals>
execution>
executions>
plugin>
plugins>
build>
打包命令:
mvn clean package
将打包出来的带有*-with-dependencies.jar的jmeter-echo-jar-with-dependencies.jar放到jmeter的lib/ext目录下:
如果打的包没问题的话,启动Jmeter,增加Sampler的时候选择Java Request:
然后选择我们定义的EchoTest:
运行下看下效果: