Jmeter 5.6.3 自定义GRPC 压测插件,配置,使用,

前言

jmeter 版本 apache-jmeter-5.6.3

说明

jmeter 自定义grpc 压测扩展实现源码,适用对grpc双向通信进行压力测试,其他grpc模式实现都非常一致。调整下代码即可实现。

使用方法:编译工程打包成jar文件,然后放到jmeter的jar目录下,以我本地为例: D:\soft\apache-jmeter-5.6.3\lib\ext

启动jmeter 进行测试

三、配置与使用
1)添加线程组:右键单击测试计划 → 添加 → 线程(用户) → 线程组

在这里插入图片描述

2) 添加GRPC Request:右键单击新建的线程组 → 添加 → 取样器 → GRPC Request

在这里插入图片描述

3)填写请求信息:主机、端口、proto文件夹、rpc方法、请求数据

在这里插入图片描述

必填项:
在这里插入图片描述

java插件核心代码

package org.apache.nifi.processors.grpc;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.grpc.CompressorRegistry;
import io.grpc.DecompressorRegistry;
import io.grpc.ManagedChannel;
import io.grpc.netty.NettyChannelBuilder;
import io.grpc.stub.StreamObserver;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.protocol.java.sampler.JavaSamplerClient;
import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
import org.apache.jmeter.samplers.SampleResult;

import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

/**
 * Created by zyq on 2020/3/4.
 */
public class GrpcJmeter implements JavaSamplerClient {
    private String userAccount;
    private String password;
    private String address;
    private Integer port;

    private String routingKey;
    private String routingSecret;

    private SampleResult results;

    private StreamObserver<org.apache.nifi.processors.grpc.gen.edge.v1.RequestMsg> inputStream;

    private ManagedChannel channel;

    private CountDownLatch countDownLatch;


    private static final String USER_AGENT_PREFIX = "NiFi_invokeGRPC";



    @Override
    public void setupTest(JavaSamplerContext javaSamplerContext) {

        countDownLatch = new CountDownLatch(1);
        results = new SampleResult();

        userAccount = javaSamplerContext.getParameter("userAccount"); // 获取在JMeter中设置的参数值
        password = javaSamplerContext.getParameter("password"); // 获取在JMeter中设置的参数值
        address = javaSamplerContext.getParameter("address"); // 获取在JMeter中设置的参数值
        port =Integer.valueOf(javaSamplerContext.getParameter("port")) ; // 获取在JMeter中设置的参数值
        routingKey = javaSamplerContext.getParameter("routingKey");
        routingSecret = javaSamplerContext.getParameter("routingSecret");

        String userAgent = USER_AGENT_PREFIX;
        try {
            userAgent += "_" + InetAddress.getLocalHost().getHostName();
        } catch (final UnknownHostException e) {
            //System.out.println("Unable to determine local hostname. Defaulting gRPC user agent to {}.", new Object[]{USER_AGENT_PREFIX}, e);
        }

        final NettyChannelBuilder nettyChannelBuilder = NettyChannelBuilder.forAddress(address, port)
                // supports both gzip and plaintext, but will compress by default.
                .compressorRegistry(CompressorRegistry.getDefaultInstance())
                .decompressorRegistry(DecompressorRegistry.getDefaultInstance())
                .maxInboundMessageSize(50000)
                .userAgent(userAgent)
                .usePlaintext();

        channel = nettyChannelBuilder.build();

        //sendCountDownLatch = new CountDownLatch(1);
        //channel = ManagedChannelBuilder.forAddress(address, port).usePlaintext().build();
        //EdgeRpcServiceGrpc.EdgeRpcServiceBlockingStub stub = EdgeRpcServiceGrpc.newBlockingStub(channel);
        org.apache.nifi.processors.grpc.gen.edge.v1.EdgeRpcServiceGrpc.EdgeRpcServiceStub stub = org.apache.nifi.processors.grpc.gen.edge.v1.EdgeRpcServiceGrpc.newStub(channel);
        inputStream = stub.withCompression("gzip").handleMsgs(initOutputStream(results,countDownLatch,routingKey, this::onUplinkResponse,this::onError));
        inputStream.onNext(org.apache.nifi.processors.grpc.gen.edge.v1.RequestMsg.newBuilder()
                .setMsgType(org.apache.nifi.processors.grpc.gen.edge.v1.RequestMsgType.CONNECT_RPC_MESSAGE)
                .setConnectRequestMsg(org.apache.nifi.processors.grpc.gen.edge.v1.ConnectRequestMsg.newBuilder()
                        .setEdgeRoutingKey(routingKey)
                        .setEdgeSecret(routingSecret)
                        .setEdgeVersion(org.apache.nifi.processors.grpc.gen.edge.v1.EdgeVersion.V_3_6_0)
                        .setMaxInboundMessageSize(419820)
                        .build())
                .build());
    }
    @Override
    public SampleResult runTest(JavaSamplerContext javaSamplerContext) {

        results.sampleStart();// JMeter 开始统计响应时间标记

        try {
            String sourceMsg = "{'key1':'value1','key2':'value1','key3':'value1','key4':'value1','key5':'value1','key6':'value1','key7':'value1','key8':'value1','key9':'value1','key11':'value1','key12':'value1','key13':'value1','key14':'value1','key15':'value1','key16':'value1','key17':'value1','key18':'value1','key19':'value1','key21':'valuie2"+ Math.random()+ "'}";

            results.setRequestHeaders(sourceMsg);
            results.setSamplerData(sourceMsg);
            results.setDataType(SampleResult.TEXT);
            org.apache.nifi.processors.grpc.gen.edge.v1.UplinkMsg msg = buildUpLinkMsg(sourceMsg);

            org.apache.nifi.processors.grpc.gen.edge.v1.RequestMsg requestMsg = org.apache.nifi.processors.grpc.gen.edge.v1.RequestMsg.newBuilder()
                    .setMsgType(org.apache.nifi.processors.grpc.gen.edge.v1.RequestMsgType.UPLINK_RPC_MESSAGE)
                    .setUplinkMsg(msg)
                    .build();
            inputStream.onNext(requestMsg);

            results.setSentBytes(JSON.toJSONString(requestMsg).getBytes().length);

            countDownLatch.await(10, TimeUnit.MILLISECONDS);
            //results.setSuccessful(true);
        } catch (Exception e){
            e.printStackTrace();
            results.setSuccessful(false);
            results.setResponseCode("500");
            results.setResponseMessage(e.getMessage());
            //results.setResponseData(("exception," + e.getMessage()).getBytes());
            //results.setResponseData(e.getMessage(),"UTF-8");
        } finally {
            /*if(Objects.nonNull(inputStream)){
                inputStream.onCompleted();
                inputStream = null;
            }
            if (channel!=null){
                channel.shutdown();
            }*/
            //results.sampleEnd();
        }
        results.sampleEnd();

        return results;
    }
    @Override
    public void teardownTest(JavaSamplerContext javaSamplerContext) {
        if(Objects.nonNull(inputStream)){
            inputStream.onCompleted();
            inputStream = null;
        }
        if (channel!=null){
            channel.shutdown();
        }
    }
    @Override
    public Arguments getDefaultParameters() {
        Arguments params = new Arguments();
        params.addArgument("userAccount", "key55555");//设置参数,并赋予默认值
        params.addArgument("password", "s55555");//设置参数,并赋予默认值
        params.addArgument("routingKey", "key55555");//设置参数,并赋予默认值
        params.addArgument("routingSecret", "s55555");//设置参数,并赋予默认值
        params.addArgument("address", "127.0.0.1");//设置参数,并赋予默认值
        params.addArgument("port", "7070");//设置参数,并赋予默认值
        return params;
    }



    private static StreamObserver<org.apache.nifi.processors.grpc.gen.edge.v1.ResponseMsg> initOutputStream(SampleResult results,CountDownLatch countDownLatch,String edgeKey,
                                                                                                            Consumer<org.apache.nifi.processors.grpc.gen.edge.v1.UplinkResponseMsg> onUplinkResponse, Consumer<Exception> onError) {
        return new StreamObserver<org.apache.nifi.processors.grpc.gen.edge.v1.ResponseMsg>() {
            @Override
            public void onNext(org.apache.nifi.processors.grpc.gen.edge.v1.ResponseMsg responseMsg) {
                if (responseMsg.hasConnectResponseMsg()) {
                    org.apache.nifi.processors.grpc.gen.edge.v1.ConnectResponseMsg connectResponseMsg = responseMsg.getConnectResponseMsg();

                    /*if(Objects.nonNull(results)){
                        results.setSuccessful(true);
                    }*/
                    System.out.println("收到服务端连接回复消息" + connectResponseMsg);
                } else if (responseMsg.hasUplinkResponseMsg()) {
                    countDownLatch.countDown();
                    System.out.println("收到服务端响应消息" + responseMsg.getUplinkResponseMsg());
                    if(responseMsg.getUplinkResponseMsg().getSuccess()){
                        results.setSuccessful(true);
                        results.setResponseCodeOK();
                        results.setResponseMessage(String.valueOf(responseMsg.getUplinkResponseMsg().getSuccess()));
                        results.setResponseData(JSON.toJSONString(responseMsg.getUplinkResponseMsg()),"UTF-8");
                    } else {
                        results.setSuccessful(false);
                        results.setResponseCode("500");
                        results.setResponseMessage(responseMsg.getUplinkResponseMsg().getErrorMsg());
                        results.setResponseData(JSON.toJSONString(responseMsg.getUplinkResponseMsg()),"UTF-8");
                    }
                    //onUplinkResponse.accept(responseMsg.getUplinkResponseMsg());
                }
            }

            @Override
            public void onError(Throwable t) {
                t.printStackTrace();
                countDownLatch.countDown();
                //onError.accept(new RuntimeException(t));
                System.out.println("断开了" + edgeKey);
                results.setSuccessful(false);
                results.setResponseMessage(t.getMessage());
                results.setResponseData("exception," + t.getMessage(), "UTF-8");
                //results.setResponseData(t.getMessage(),"UTF-8");

            }

            @Override
            public void onCompleted() {
                countDownLatch.countDown();
                System.out.println("[{}] Stream was closed and completed successfully!" + edgeKey);
            }
        };
    }

    private void onError(final Exception e){
        results.setSuccessful(false);
        results.setResponseMessage(e.getMessage());
        results.setResponseData(e.getMessage(),"UTF-8");
    }

    private void onUplinkResponse(org.apache.nifi.processors.grpc.gen.edge.v1.UplinkResponseMsg msg) {
        //设置响应的数据,这里设置后,在JMeter的察看结果树中才可显示
        results.setSuccessful(true);
        results.setResponseMessage(JSON.toJSONString(msg));
        results.setResponseData(JSON.toJSONString(msg),"UTF-8");
    }

    private org.apache.nifi.processors.grpc.gen.edge.v1.UplinkMsg buildUpLinkMsg(String jsonMeg) throws JsonProcessingException {
        UUID entityId = UUID.randomUUID();
        org.apache.nifi.processors.grpc.gen.edge.v1.EntityDataProto.Builder builder = org.apache.nifi.processors.grpc.gen.edge.v1.EntityDataProto.newBuilder()
                .setEntityIdMSB(entityId.getMostSignificantBits())
                .setEntityIdLSB(entityId.getLeastSignificantBits())
                .setEntityType("device");
        long ts = System.currentTimeMillis();
        builder.setJsonData(jsonMeg);
        org.apache.nifi.processors.grpc.gen.edge.v1.EntityDataProto entityDataProto = builder.build();
        return  org.apache.nifi.processors.grpc.gen.edge.v1.UplinkMsg.newBuilder()
                .setUplinkMsgId(EdgeUtils.nextPositiveInt())
                .addEntityData(entityDataProto)
                .build();
    }

}

源码下载

[https://download.youkuaiyun.com/download/gzcsschen/89427899]

源码如何使用

编译源码

在这里插入图片描述

拷贝编译好的jar 到 jmeter 目录下的 /lib/ext/目录下

在这里插入图片描述

重新启动jmeter,在add java request 里面会多一个 grpc的选项,并且会自动识别proto文件

在这里插入图片描述

选择grpc 选项

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gzcsschen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值