如何用Jmeter压测Netty的Echo服务之自定义Jmeter的Java Sampler

前言

如果想要压测一些三方组件,比如MQ,redis什么的,jmeter本身是不支持的。
本文以开发一个压测netty的echo示例,说明如何自定义jmeter的sampler。

开发

本文以idea示例,

新建工程

打开idea新建一个空的maven工程:
如何用Jmeter压测Netty的Echo服务之自定义Jmeter的Java Sampler_第1张图片

pom依赖

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>

Echo客户端

这部分代码可以从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);
    }
}

开发Jmeter的JavaSampler

@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

打包完成,在target目录下生成如下jar包:
如何用Jmeter压测Netty的Echo服务之自定义Jmeter的Java Sampler_第2张图片

部署

将打包出来的带有*-with-dependencies.jar的jmeter-echo-jar-with-dependencies.jar放到jmeter的lib/ext目录下:
如何用Jmeter压测Netty的Echo服务之自定义Jmeter的Java Sampler_第3张图片

启动jmeter

如果打的包没问题的话,启动Jmeter,增加Sampler的时候选择Java Request:
如何用Jmeter压测Netty的Echo服务之自定义Jmeter的Java Sampler_第4张图片
然后选择我们定义的EchoTest:
如何用Jmeter压测Netty的Echo服务之自定义Jmeter的Java Sampler_第5张图片
运行下看下效果:
如何用Jmeter压测Netty的Echo服务之自定义Jmeter的Java Sampler_第6张图片
在这里插入图片描述

你可能感兴趣的:(测试,网络协议,java,jmeter,Netty,Sampler)