前言
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 选项

1万+

被折叠的 条评论
为什么被折叠?



