用jmeter-grpc-request性能测试的严重问题

起因今日收到一个同事的求救信息,说正在做gRPC接口测试,用的是jmeter的一个第三方插件,叫jmeter-grpc-request,平日用着挺好用的,今天设置了100个线程,持续跑,结果才跑了5000来个请求,就卡住了。卡住了?什么是卡住了呢?我仔细问了,才知道是jmeter整个没有响应了,只能强行杀进程才能停止。这是怎么回事呢?场景重现我问同事要了jmeter的脚本文件,并且下载了这个gRPC取样器的插件,在我本机试了一下,果然,线程数量很少时候,运行正常,但是数量多了一些(仅仅到了50.
摘要由CSDN通过智能技术生成

在这里插入图片描述

起因

今日收到一个同事的求救信息,说正在做gRPC接口测试,用的是jmeter的一个第三方插件,叫jmeter-grpc-request,平日用着挺好用的,今天设置了100个线程,持续跑,结果才跑了5000来个请求,就卡住了。

卡住了?什么是卡住了呢?

我仔细问了,才知道是jmeter整个没有响应了,只能强行杀进程才能停止。这是怎么回事呢?

在这里插入图片描述

场景重现

我问同事要了jmeter的脚本文件,并且下载了这个gRPC取样器的插件,在我本机试了一下,果然,线程数量很少时候,运行正常,但是数量多了一些(仅仅到了50),很快就出现了jmeter无响应的情况。

根据经验,立刻切到启动jmeter的命令行界面,看到的提示是内存溢出(OutOfMemoryException)。

这是很奇怪的现象,按理来说,仅仅是50个线程,才跑了几千的请求量,怎么就内存溢出了呢?我们知道,jmeter默认的运行内存是1G(HEAP=”-Xms1g -Xmx1g -XX:MaxMetaspaceSize=256m”)几千的请求量,什么东西占用了1G的Heap空间?

内存分析

jmeter工具还是挺方便的,在出现了内存溢出后,自动dump出了此时的JVM情况,在当前的运行目录下生成了java_pid.hprof文件(id是当时jmeter的进程ID)。

所以我用jhat命令来读取hprof文件,看看到底什么东西占用了这么多内存:

$ jhat -port 7001 java_pid<id>.hprof

这里我用了-port参数指定了7001端口,因为默认的7000端口已经被我机器上别的程序占用了。

经过一段时间的等待(dump出来的hprof文件文件太大了,上G),命令行提示已读取完成,此时jhat会启动一个Web服务器,打开浏览器输入http://localhost:7001就可以看到jvm中加载的所有对象。

当然,我要看的是Heap中这些对象的占用空间情况,所以通过最底下的链接,切换到了heap内存分析页:

很明显,排在前几行的就是“罪魁祸首”了。

也许有的小伙伴不清楚,class [B是什么,其实就是java中的byte数组,居然占了300多MB的内存空间。

其次,就是FiledDescriptor对象,占了200多MB的内存空间。这两个大户,耗费了一半的Heap内存,难怪内存不够了。

那么现在的问题就在于两个地方,

这个byte数组,存了什么,为何这么多;

这个FiledDescriptor为何这么多实例。

这就只能从代码角度来分析了。

代码分析

根据对jmeter组件开发的了解,代码从继承AbstractSampler的Sampler开始。当在jmeter中开始运行取样器时,执行的就是sample方法,仔细看看sampler中的sample方法:

@Override
public SampleResult sample(Entry ignored) {
   
    GrpcResponse grpcResponse = new GrpcResponse();
    SampleResult sampleResult = new SampleResult();
    try {
   
        initGrpcClient();
        sampleResult.setSampleLabel(getName());
        String grpcRequest = clientCaller.buildRequestAndMetadata(getRequestJson(),getMetadata());
        sampleResult.setSamplerData(grpcRequest);
        sampleResult.setRequestHeaders(clientCaller.getMetadataString());
        sampleResult.sampleStart();
        grpcResponse = clientCaller.call(getDeadline());
        sampleResult.sampleEnd();
        sampleResult.setSuccessful(true);
        sampleResult.setResponseData(grpcResponse.getGrpcMessageString().getBytes(StandardCharsets.UTF_8));
        sampleResult.setResponseMessage
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值