Jmeter protobuf 测试。无法读取 Protobuf 消息

Posted

技术标签:

【中文标题】Jmeter protobuf 测试。无法读取 Protobuf 消息【英文标题】:Jmeter protobuf testing. Could not read Protobuf message 【发布时间】:2015-11-17 09:18:40 【问题描述】:

我正在通过 protobuf 协议并使用 HTTP Request Sampler 测试一个项目。目标应用服务器也是用 Java 编写的。 响应中有错误的问题:

“无法读取 Protobuf 消息:协议消息包含 无效标签(零)。;嵌套异常是 com.google.protobuf.InvalidProtocolBufferException:协议消息 包含无效标签(零)”

情况是它不是在 100% 的请求中发生。当我使用 HttpClient4 时,大约有 30-40% 的失败请求。在我将其更改为 HttpClient3.1 后,错误率下降到 ~10%,这也不是什么好事。

要发送 protobuf 消息,我在 HttpSampler 的 Bodydata 选项卡中使用变量 $data。在 BeanShell 预处理器中,我执行以下操作:

(import and non-necessary stuff were ommited)
MapViewport mv = MapRequest.MapViewport.newBuilder().setMaxX(mc.getX()+15).setMaxY(mc.getY()+15).setMinX(mc.getX()-15).setMinY(mc.getY()-15).build();

byte[] data = mv.toByteArray();
vars.put("data", new String(data));

我还尝试使用不同的编码,例如 new String(data,"UTF-8") 等等。

如果在查看结果树的情况下查看请求选项卡,我可以说所有失败的消息都包含“?”符号:

似乎不应该发送一些奇怪的符号,但是在将字节数组保存到 String 后,大约 10% 的请求包含它们。

【问题讨论】:

因此,您将二进制流转换为字符串以另存为 var - 根据编码,这可能会充满问题。它也依赖于系统,行为可以改变。此外,当您是$data 时,您正在发送一个字符串,该字符串对于某些二进制数据正在插入? 想到的第一个解决方法是将二进制流写入文件并将文件路径用作bodydata 中的变量.但这会导致大量文件 I/O 用于大容量。嗯..这有点思想家。 另外,您可以组装自己的 HTTP 请求并从 beanshell 采样器发送它,而不是使用 HTTP 采样器。想知道 jmeter-plugins 中的 HTTP Raw Request 是否有用。 【参考方案1】:

我相当确信您的问题是您在从二进制流转换为字符串然后再转换回来时丢失了一些不可打印的字符。我正在考虑两种可能的解决方法:

    将二进制数据写入文件而不是保存为字符串,然后将文件名用作 HTTP 采样器中的变量,位于文件部分的正文中

    使用 beanshell 采样器,构建您自己的 HTTPClient 对象和 POST 请求,将二进制数据放在正文中并自行触发,而不是使用 HTTP 采样器

我不喜欢第一个选项,因为所有额外的文件 I/O。我不喜欢第二个选项,因为测量响应时间现在将包括您在 beanshell 中执行的所有请求组装 - 所以您必须选择一个我猜您不那么麻烦的。

如果您希望我为这两种情况编写一些代码示例,请告诉我。

编辑:对于使用 HttpClient 4 的 beanshell HTTP 调用:

import org.apache.http.HttpEntity;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.DefaultHttpClient;

byte[] data = null;
//...assign protobuf binary buffer to data...

HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost("http://127.0.0.1");
HttpEntity entity = new ByteArrayEntity(data);
post.setEntity(entity);
post.setHeader(HttpHeaders.CONTENT_TYPE, "application/octet-stream");
HttpResponse response=null;
try 
    response = client.execute(post);
 catch (ClientProtocolException e) 
    // TODO Auto-generated catch block
    e.printStackTrace();
 catch (IOException e) 
    // TODO Auto-generated catch block
    e.printStackTrace();


ResponseCode = response.getStatusLine().getStatusCode().toString();
//if some assert is true then
Issuccess = true;
ResponseMessage="Some Response Message";

这未针对 protobuf 端点进行测试,请告诉我它对您的效果。

【讨论】:

也许对数据进行 base64 编码会有所帮助? (FWIW,这个问题肯定是由于试图将非文本二进制数据推入Strings——这永远行不通。) @RaGe 你能提供一些 Beanshell 中 HTTPClient 的例子吗? 用一些代码更新。我针对常规的 http 端点进行了测试,但没有针对 protobuf 端点进行测试,手边没有。【参考方案2】:

在高负载时,Beanshell 解释器可能会导致意外行为,因为它存在一些性能问题。尝试切换到JSR223 PreProcessor 并使用groovy 作为语言。 Groovy 脚本引擎实现了Compilable 接口,因此只要您遵循一些简单的规则,您可以获得最佳性能并且您的问题可以消失。

请参阅Beanshell vs JSR223 vs Java JMeter Scripting: The Performance-Off You've Been Waiting For! 文章,了解 groovy 引擎安装说明、脚本最佳实践以及 Beanshell 与 Groovy 基准测试。

【讨论】:

试过JSR223 PreProcessor 结果完全一样:( @v0devil 您的问题是您正在从二进制数据转换为字符串并返回,并且在转换中丢失了一些不可打印的字符。 Beanshell 稳定性不是问题。 @RaGe 是的,看起来像。我没有收到您关于使用 HTTP 原始请求的评论 - 那将是相同的方式,不是吗? 我没有使用原始请求采样器,但我希望它可以更好地控制您可以放入 POST 正文的内容

以上是关于Jmeter protobuf 测试。无法读取 Protobuf 消息的主要内容,如果未能解决你的问题,请参考以下文章

性能测试:Jmeter压测过程中的短信验证码读取

无法使用 Google 的 protobuf 构建测试 C++ 应用程序

Jmeter使用csv文件读取测试数据

JMETER接口测试问题三之JMETER读取文档中文编码问题的修改

用于从流中读取多个 protobuf 消息的 python 示例

WEB接口测试之Jmeter接口测试自动化 (数据驱动测试) 接口测试与数据驱动