前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >「IM系列」WebSocket教程:如何使用JMeter进行压力测试

「IM系列」WebSocket教程:如何使用JMeter进行压力测试

作者头像
Tinywan
发布2023-12-19 17:13:05
8210
发布2023-12-19 17:13:05
举报
文章被收录于专栏:开源技术小栈开源技术小栈

JMeter

JMeter 是目前最为流行的开源性能测试工具,JMeter 本身提供的基于插件的机制允许第三方实现标准 JMeter 所不支持的协议,而 WebSocket 的一个比较好的实现是 WebSocketSampler 。利用此插件,能完成基于 WebSocket 协议的基本性能测试。

安装

下载地址:https://jmeter.apache.org/download_jmeter.cgi

Windows直接下载二进制文件即可

将下载的文件复制/移动到本地目录下。我这里是直接复制到D盘,D:\apache-jmeter-5.4.1

安装Websocket插件包

下载地址:https://bitbucket.org/pjtr/jmeter-websocket-samplers/downloads/

将下载的文件复制/移动到D:\apache-jmeter-5.4.1\lib\ext目录下

启动Jmeter

进入可执行目录D:\apache-jmeter-5.4.1\bin查找批处理文件jmeter.bat

先添加线程组Tinywan Thread Group,再点击添加sampler,就可以看到websocket信息

以上截图表示插件安装成功。

编写测试计划

这里按照之前编写教程填写相关参数即可

代码语言:javascript
复制
var ws = new WebSocket("ws://127.0.0.1:8783");

开源技术小栈测试计划.jmx

1. 连接

选择协议ws/wss,输入ip端口路径请求参数(没有参数可不填)

2.0 加入群聊

JMeter

代码语言:javascript
复制
let $_content = {
  "event": "join",
  "mode": 2,
  "group_id": 100,
  "from_user_id": "10086",
  "from_username": "阿克苏",
  "to_user_id": "10000",
  "content": "加入会话",
};
console.log(JSON.stringify($_content))

JSON.stringify() 方法将一个 JavaScript 对象或值转换为 JSON 字符串。

解析以上转换为JSON字符串

代码语言:javascript
复制
{"event":"join","mode":2,"group_id":100,"from_user_id":"10086","from_username":"阿克苏","to_user_id":"10000","content":"加入会话"}

3.0 说话

需要发送的请求内容

代码语言:javascript
复制
let content = {
      "event": "speak",
      "mode": 2,
      "group_id": 100,
      "from_user_id": "10086",
      "from_username": "阿克苏",
      "to_user_id": "10000",
      "content": "WebSocket教程:消息持久化的实现与应用",
   }
console.log(JSON.stringify(content))

JSON.stringify() 方法将一个 JavaScript 对象或值转换为 JSON 字符串。

解析以上转换为JSON字符串

代码语言:javascript
复制
{"event":"speak","mode":2,"group_id":100,"from_user_id":"10086","from_username":"阿克苏","to_user_id":"10000","content":"WebSocket教程:消息持久化的实现与应用"}

4. 心跳

创建循环控制器

添加 WebSocket Sampler

请求内容

代码语言:javascript
复制
{"event":"ping","content":"ping heartbeat"}

5. 添加查看结果树

上图就是执行结果的查看树,可以在右边的窗口中看到取样器结果、请求、响应数据,其中,请求是客户端向服务器发送的请求,响应数据是服务器接收请求后返回的结果,可以选择不同的结果查看方式,有json、html、xpath等等。

6. 添加聚合报告

运行JMeter

1.0 连接

请求数据

响应数据

2.0 说话

请求数据

响应数据

聚合报告看性能

  • Samples:样本总数量,等于线程总数 * 循环次数。
  • Average:请求处理的平均时间(毫秒ms),是压力测试的主要指标之一 。
  • Median:请求处理的中值时间(毫秒ms),样本数量中有一半的处理时间在这个值之上,有一半的处理时间在这个值之下。
  • 90%Line,95%Line,99%Line:样本中百分之多少的处理时间都在这个值之下,是压力测试的主要指标之一。
  • Min:耗时最少的请求时间。
  • Max:耗时最多的请求时间。
  • Error%:错误率。
  • Throughput:吞吐量,服务器每秒处理的请求数。
  • KB/sec:服务器每秒钟请求的字节数。

其他

JMeter 压测脚本

下载地址:https://github.com/Tinywan/webman-admin/blob/main/db/开源技术小栈测试计划.jmx

开源技术小栈测试计划.jmx

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.4.1">
  <hashTree>
    <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="开源技术小栈测试计划" enabled="true">
      <stringProp name="TestPlan.comments"></stringProp>
      <boolProp name="TestPlan.functional_mode">false</boolProp>
      <boolProp name="TestPlan.serialize_threadgroups">true</boolProp>
      <elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
        <collectionProp name="Arguments.arguments">
          <elementProp name="username" elementType="Argument">
            <stringProp name="Argument.name">username</stringProp>
            <stringProp name="Argument.value">Tinywan</stringProp>
            <stringProp name="Argument.metadata">=</stringProp>
          </elementProp>
          <elementProp name="password" elementType="Argument">
            <stringProp name="Argument.name">password</stringProp>
            <stringProp name="Argument.value">xxxx</stringProp>
            <stringProp name="Argument.metadata">=</stringProp>
          </elementProp>
        </collectionProp>
      </elementProp>
      <stringProp name="TestPlan.user_define_classpath"></stringProp>
    </TestPlan>
    <hashTree>
      <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Im Websocket 压测" enabled="true">
        <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
        <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="循环控制器" enabled="true">
          <boolProp name="LoopController.continue_forever">false</boolProp>
          <stringProp name="LoopController.loops">500</stringProp>
        </elementProp>
        <stringProp name="ThreadGroup.num_threads">1</stringProp>
        <stringProp name="ThreadGroup.ramp_time">1</stringProp>
        <boolProp name="ThreadGroup.scheduler">false</boolProp>
        <stringProp name="ThreadGroup.duration"></stringProp>
        <stringProp name="ThreadGroup.delay"></stringProp>
        <boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp>
      </ThreadGroup>
      <hashTree>
        <CriticalSectionController guiclass="CriticalSectionControllerGui" testclass="CriticalSectionController" testname="临界部分控制器" enabled="false">
          <stringProp name="CriticalSectionController.lockName">global_lock</stringProp>
        </CriticalSectionController>
        <hashTree/>
        <eu.luminis.jmeter.wssampler.OpenWebSocketSampler guiclass="eu.luminis.jmeter.wssampler.OpenWebSocketSamplerGui" testclass="eu.luminis.jmeter.wssampler.OpenWebSocketSampler" testname="1.0 连接" enabled="true">
          <boolProp name="TLS">false</boolProp>
          <stringProp name="server">127.0.0.1</stringProp>
          <stringProp name="port">8783</stringProp>
          <stringProp name="path">/?sign=ca7a2df4c9850239ded1974f5abe8fc7&amp;ws_timestamp=1636079196</stringProp>
          <stringProp name="connectTimeout">20000</stringProp>
          <stringProp name="readTimeout">6000</stringProp>
        </eu.luminis.jmeter.wssampler.OpenWebSocketSampler>
        <hashTree/>
        <eu.luminis.jmeter.wssampler.RequestResponseWebSocketSampler guiclass="eu.luminis.jmeter.wssampler.RequestResponseWebSocketSamplerGui" testclass="eu.luminis.jmeter.wssampler.RequestResponseWebSocketSampler" testname="2.0 加入群聊" enabled="true">
          <boolProp name="createNewConnection">false</boolProp>
          <boolProp name="TLS">false</boolProp>
          <stringProp name="server"></stringProp>
          <stringProp name="port">80</stringProp>
          <stringProp name="path"></stringProp>
          <stringProp name="connectTimeout">20000</stringProp>
          <boolProp name="binaryPayload">false</boolProp>
          <stringProp name="requestData">{&quot;event&quot;:&quot;join&quot;,&quot;mode&quot;:2,&quot;group_id&quot;:100,&quot;from_user_id&quot;:&quot;10086&quot;,&quot;from_username&quot;:&quot;阿克苏&quot;,&quot;to_user_id&quot;:&quot;10000&quot;,&quot;content&quot;:&quot;加入会话&quot;}</stringProp>
          <stringProp name="readTimeout">6000</stringProp>
          <boolProp name="loadDataFromFile">false</boolProp>
          <stringProp name="dataFile"></stringProp>
        </eu.luminis.jmeter.wssampler.RequestResponseWebSocketSampler>
        <hashTree/>
        <eu.luminis.jmeter.wssampler.RequestResponseWebSocketSampler guiclass="eu.luminis.jmeter.wssampler.RequestResponseWebSocketSamplerGui" testclass="eu.luminis.jmeter.wssampler.RequestResponseWebSocketSampler" testname="3.0 说话" enabled="true">
          <boolProp name="createNewConnection">false</boolProp>
          <boolProp name="TLS">false</boolProp>
          <stringProp name="server"></stringProp>
          <stringProp name="port">80</stringProp>
          <stringProp name="path"></stringProp>
          <stringProp name="connectTimeout">20000</stringProp>
          <boolProp name="binaryPayload">false</boolProp>
          <stringProp name="requestData">{&quot;event&quot;:&quot;speak&quot;,&quot;mode&quot;:2,&quot;group_id&quot;:100,&quot;from_user_id&quot;:&quot;10086&quot;,&quot;from_username&quot;:&quot;阿克苏&quot;,&quot;to_user_id&quot;:&quot;10000&quot;,&quot;content&quot;:&quot;WebSocket教程:消息持久化的实现与应用&quot;}</stringProp>
          <stringProp name="readTimeout">6000</stringProp>
          <boolProp name="loadDataFromFile">false</boolProp>
          <stringProp name="dataFile"></stringProp>
        </eu.luminis.jmeter.wssampler.RequestResponseWebSocketSampler>
        <hashTree/>
        <ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="察看结果树" enabled="true">
          <boolProp name="ResultCollector.error_logging">false</boolProp>
          <objProp>
            <name>saveConfig</name>
            <value class="SampleSaveConfiguration">
              <time>true</time>
              <latency>true</latency>
              <timestamp>true</timestamp>
              <success>true</success>
              <label>true</label>
              <code>true</code>
              <message>true</message>
              <threadName>true</threadName>
              <dataType>true</dataType>
              <encoding>false</encoding>
              <assertions>true</assertions>
              <subresults>true</subresults>
              <responseData>false</responseData>
              <samplerData>false</samplerData>
              <xml>false</xml>
              <fieldNames>true</fieldNames>
              <responseHeaders>false</responseHeaders>
              <requestHeaders>false</requestHeaders>
              <responseDataOnError>false</responseDataOnError>
              <saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
              <assertionsResultsToSave>0</assertionsResultsToSave>
              <bytes>true</bytes>
              <sentBytes>true</sentBytes>
              <url>true</url>
              <threadCounts>true</threadCounts>
              <idleTime>true</idleTime>
              <connectTime>true</connectTime>
            </value>
          </objProp>
          <stringProp name="filename"></stringProp>
        </ResultCollector>
        <hashTree/>
        <ResultCollector guiclass="SummaryReport" testclass="ResultCollector" testname="汇总报告" enabled="true">
          <boolProp name="ResultCollector.error_logging">false</boolProp>
          <objProp>
            <name>saveConfig</name>
            <value class="SampleSaveConfiguration">
              <time>true</time>
              <latency>true</latency>
              <timestamp>true</timestamp>
              <success>true</success>
              <label>true</label>
              <code>true</code>
              <message>true</message>
              <threadName>true</threadName>
              <dataType>true</dataType>
              <encoding>false</encoding>
              <assertions>true</assertions>
              <subresults>true</subresults>
              <responseData>false</responseData>
              <samplerData>false</samplerData>
              <xml>false</xml>
              <fieldNames>true</fieldNames>
              <responseHeaders>false</responseHeaders>
              <requestHeaders>false</requestHeaders>
              <responseDataOnError>false</responseDataOnError>
              <saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
              <assertionsResultsToSave>0</assertionsResultsToSave>
              <bytes>true</bytes>
              <sentBytes>true</sentBytes>
              <url>true</url>
              <threadCounts>true</threadCounts>
              <idleTime>true</idleTime>
              <connectTime>true</connectTime>
            </value>
          </objProp>
          <stringProp name="filename"></stringProp>
        </ResultCollector>
        <hashTree/>
        <ResultCollector guiclass="StatVisualizer" testclass="ResultCollector" testname="聚合报告" enabled="true">
          <boolProp name="ResultCollector.error_logging">false</boolProp>
          <objProp>
            <name>saveConfig</name>
            <value class="SampleSaveConfiguration">
              <time>true</time>
              <latency>true</latency>
              <timestamp>true</timestamp>
              <success>true</success>
              <label>true</label>
              <code>true</code>
              <message>true</message>
              <threadName>true</threadName>
              <dataType>true</dataType>
              <encoding>false</encoding>
              <assertions>true</assertions>
              <subresults>true</subresults>
              <responseData>false</responseData>
              <samplerData>false</samplerData>
              <xml>false</xml>
              <fieldNames>true</fieldNames>
              <responseHeaders>false</responseHeaders>
              <requestHeaders>false</requestHeaders>
              <responseDataOnError>false</responseDataOnError>
              <saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
              <assertionsResultsToSave>0</assertionsResultsToSave>
              <bytes>true</bytes>
              <sentBytes>true</sentBytes>
              <url>true</url>
              <threadCounts>true</threadCounts>
              <idleTime>true</idleTime>
              <connectTime>true</connectTime>
            </value>
          </objProp>
          <stringProp name="filename"></stringProp>
        </ResultCollector>
        <hashTree/>
        <LoopController guiclass="LoopControlPanel" testclass="LoopController" testname="循环控制器" enabled="true">
          <boolProp name="LoopController.continue_forever">true</boolProp>
          <stringProp name="LoopController.loops">500</stringProp>
        </LoopController>
        <hashTree>
          <ConstantTimer guiclass="ConstantTimerGui" testclass="ConstantTimer" testname="固定定时器" enabled="true">
            <stringProp name="ConstantTimer.delay">10000</stringProp>
          </ConstantTimer>
          <hashTree/>
          <eu.luminis.jmeter.wssampler.RequestResponseWebSocketSampler guiclass="eu.luminis.jmeter.wssampler.RequestResponseWebSocketSamplerGui" testclass="eu.luminis.jmeter.wssampler.RequestResponseWebSocketSampler" testname="ws-心跳检测" enabled="true">
            <boolProp name="createNewConnection">false</boolProp>
            <boolProp name="TLS">false</boolProp>
            <stringProp name="server"></stringProp>
            <stringProp name="port">80</stringProp>
            <stringProp name="path"></stringProp>
            <stringProp name="connectTimeout">20000</stringProp>
            <boolProp name="binaryPayload">false</boolProp>
            <stringProp name="requestData">{&quot;event&quot;:&quot;ping&quot;,&quot;content&quot;:&quot;ping heartbeat&quot;}</stringProp>
            <stringProp name="readTimeout">6000</stringProp>
            <boolProp name="loadDataFromFile">false</boolProp>
            <stringProp name="dataFile"></stringProp>
          </eu.luminis.jmeter.wssampler.RequestResponseWebSocketSampler>
          <hashTree/>
        </hashTree>
      </hashTree>
    </hashTree>
  </hashTree>
</jmeterTestPlan>
本文参与?腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-12-18,如有侵权请联系?cloudcommunity@tencent.com 删除

本文分享自 开源技术小栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • JMeter
    • 安装
      • 安装Websocket插件包
        • 启动Jmeter
        • 编写测试计划
          • 1. 连接
            • 2.0 加入群聊
              • 3.0 说话
                • 4. 心跳
                  • 5. 添加查看结果树
                    • 6. 添加聚合报告
                    • 运行JMeter
                      • 1.0 连接
                        • 2.0 说话
                        • 聚合报告看性能
                          • 其他
                            • JMeter 压测脚本
                        领券
                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
                        http://www.vxiaotou.com