Jmeter使用Websocket插件测试SingalR,外加还有阿里云PTS的Jmeter原生测试爬坑日志。

时间:2023-03-08 16:15:37

题外话:距离我的上一篇博客已经过去7年多了,我实在是个不务正业的程序员,遇到测试方面的东西总想分享一下,因为可用的资料实在太少了(包括国外的资料)。

本人不喜欢授人以鱼,所以不会直接给出问题和解决方案的键值对,各位看官多多包涵。

先说说这次的场景:

在开发中我们使用.Net Core的SignalR(底层实现为包括WebSocket的多个协议的封装)作为长连接方案。同时对于该长连接的压力测试也是一个非常重要的环节。

坑1:Jmeter连接SingalR

我通过Chrome查看时,看到有一个连接是连到/HubName?id=XXXXXXXXXXXX,所以我果sha断bi的直接用了这个连接。一直提示404。此时觉得应该是我的插件或者Jmeter本身又或者是我老婆不让我连接这个接口。多方尝试无果,坐飞机去曾经的人类曙光查。(7年后我还是想吐槽一下百度你真的是给我们提供了一个测试Internet连接的好工具)

查到这个: 这个是病毒不要点点了地球会爆炸!

巨硬的官方文档,重点画出来,自己看大图

Jmeter使用Websocket插件测试SingalR,外加还有阿里云PTS的Jmeter原生测试爬坑日志。

这个是SignalR用来创建连接的请求,跑回Chrome一看果然有这个请求,这个请求成功后会带一个ConnectID,后面的连接可以使用这个ID做参数来连接。嗯,原来是少了这一步。少年且慢,是不是拿着葵花宝典就想着去自宫了?再继续往下看:

Jmeter使用Websocket插件测试SingalR,外加还有阿里云PTS的Jmeter原生测试爬坑日志。

是的,这里写着,若不自宫亦能成功。

原来直接去对/HubName不带queryString进行连接也可以创建连接。

至于为什么之前带参数会提示404(或者409)。上面那张图自己找去

至此,连接问题解决!手动撒花~

坑2:阿里云PTS,Jmeter原生模式运行Websocket提示“启动错误”

本来准备弄个压测服务器对等的压测。某天中午睡觉梦到蛇咬自己尾巴,然后就得出了苯的分子式的这个人并不是我。不过我确实午睡的时候突然想到有没有更便宜的方案?一查果然有云压测。在根本就没有经过分析对比的情况下我选择了阿里云PTS并且让老板给我掏了158大洋买了个云玩具。

很方便的是它可以上传jar插件和参数化csv文件,这点基本解决了压测的绝大部分问题。

在自信满满的写好了WebSocket脚本并且上传好插件之后,运行起来Duang(看我嘴型),启动错误,并且没有任何什么卵提示。提交工单吧:

然后客服GG告诉我他本地打开文件确实也Duang了,说我脚本文件是不是有问题。(这里注意以下他睾贵的标题栏,并不是瘟到死,我手上没有Mac无法确认是否是跨平台的问题)

Jmeter使用Websocket插件测试SingalR,外加还有阿里云PTS的Jmeter原生测试爬坑日志。

[手动黑人问号],继续追问下,GG很热心的帮我找到了错误的位置。

Jmeter使用Websocket插件测试SingalR,外加还有阿里云PTS的Jmeter原生测试爬坑日志。

[手动懵逼脸1秒露出淫笑],让我想起来好像Chrome调试下,在每个WebSocket内请求的结尾都会显示一个方框。并且这个方框被复制到了测试脚本中。删掉这个方框后,请求就会超时,这让我更加确认了这是一个结束符,查阅Unicode以后更加肯定了

Jmeter使用Websocket插件测试SingalR,外加还有阿里云PTS的Jmeter原生测试爬坑日志。

并且我注意到(忘了哪里找到的小道消息),1e在XML中是一个非法字符,而jmx就是xml格式。

那么我不放在脚本内部不就完了?找到脚本,勾选从发送文件内容,把包括请求内容和结束符都放到一个txt中,选择该文件。

成功启动!撒花!

坑3:接上个坑的解决方案之后

其实有一些经验的人应该注意到一个可能存在的问题:如果请求内容也放到txt中那么就无法参数化了。简单测试以后问题确认。

那么现在就在石头和硬的东西中间(Between a rock and a hard place),要么不能参数化,要么老板给我买的玩具报废。依照马克思恩格斯以及毛爷爷思想邓爷爷理论中最重要的废物利用原则,我还是想想办法吧。

Websocket的数据收发,其实和socket的数据收发形式是很像的。底层都是以字节流的方式。这也是为什么每条消息需要一个结束符来表示消息的末尾,否则服务端无法确认数据包的结束。等不到结束符SignalR也不会认为收到了消息,两边会一直等到超时为止。

既然和Socket很像,那么就有可能有粘包问题(不懂自己百度吧,我也不懂)我猜想,这里可否利用一下粘包的特性?

解决方案如下:

连接成功后,

1、创建一个WebSocket Writer,把请求内容直接写到脚本文件中,这里不发送结束符,同时不等待响应。那么这里的内容就可以参数化了

2、再创建一个WebSocket request-respone, 此时用上面文件的方式仅仅发送一个结束符,然后接收响应。

相当于把两个请求合成了一个请求,(request1&request2)-response

方案得逞,撒花!