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

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

作者头像
Tinywan
发布于 2023-12-19 09:13:05
发布于 2023-12-19 09:13:05
2.5K00
代码可运行
举报
文章被收录于专栏:开源技术小栈开源技术小栈
运行总次数:0
代码可运行

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
代码运行次数:0
运行
AI代码解释
复制
var ws = new WebSocket("ws://127.0.0.1:8783");

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

1. 连接

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

2.0 加入群聊

JMeter

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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
代码运行次数:0
运行
AI代码解释
复制
{"event":"join","mode":2,"group_id":100,"from_user_id":"10086","from_username":"阿克苏","to_user_id":"10000","content":"加入会话"}

3.0 说话

需要发送的请求内容

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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
代码运行次数:0
运行
AI代码解释
复制
{"event":"speak","mode":2,"group_id":100,"from_user_id":"10086","from_username":"阿克苏","to_user_id":"10000","content":"WebSocket教程:消息持久化的实现与应用"}

4. 心跳

创建循环控制器

添加 WebSocket Sampler

请求内容

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{"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
代码运行次数:0
运行
AI代码解释
复制
<?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 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
WireGuard 系列文章(九):基于 K3S+WireGuard+Kilo 搭建跨多云的统一 K8S 集群
2.WireGuard 系列文章(二):WireGuard 简介 - 快速、现代、安全的 V** 隧道[2]
东风微鸣
2022/04/22
3.9K0
WireGuard 系列文章(九):基于 K3S+WireGuard+Kilo 搭建跨多云的统一 K8S 集群
基于LLM的AI OPS 探索系列-配置 WireGuard连接本地AI模型和云端容器应用
本文旨在指导如何使用 WireGuard 技术打通本地 AI 模型和云端 Kubernetes 集群之间的连接,以有效利用本地 GPU 资源进行测试和开发,避免云 GPU 实例的高成本。
行者深蓝
2024/07/18
1720
wireguard-跨云or vpc网络通讯方案
早期服务器集中于腾讯云,开始是传统网络。后面是自定义的私有网络vpc.当然了vpc中还有容器网络,容器的网络方案使用了默认的Global Router,并没有使用VPC-CNI的容器网络与云主机网络在同一个 VPC 内的方案(腾讯云官方文档还有了Cilium-Overlay 的方案,恩还有个测试环境的k8s集群是kubeadm自建的集群网络插件用的cilum).今年45月份有些新业务又跑在了某云上面,集群环境直接用了某云的ACK PRO。网络插件使用了Flannel ,也没有使用某云的Terway。现在的需求就是要把两个网络打通!
对你无可奈何
2022/08/24
3.3K0
WireGuard 系列文章(八):基于 WireGuard 的 K8S CNI Kilo 简介
2.WireGuard 系列文章(二):WireGuard 简介 - 快速、现代、安全的 V** 隧道[2]
东风微鸣
2022/04/22
2.9K0
WireGuard 系列文章(八):基于 WireGuard 的 K8S CNI Kilo 简介
WireGuard 系列文章(四):WireGuard 快速上手
2.WireGuard 系列文章(二):WireGuard 简介 - 快速、现代、安全的 V** 隧道[2]
东风微鸣
2022/04/22
6.6K0
WireGuard 系列文章(四):WireGuard 快速上手
wireguard安装与配置
https://www.cnblogs.com/syy1757528181/p/14333389.html
墨文
2021/06/09
13.9K1
wireguard安装与配置
有了这款图形管理界面,一分钟内配置 10 个 WireGuard 客户端不是梦
该文章随时会有校正更新,公众号无法更新,欢迎订阅博客查看最新内容:https://fuckcloudnative.io 前言 之前花了很大的篇幅介绍了 WireGuard 的?工作原理和?配置详解,可
米开朗基杨
2021/01/28
15.6K0
有了这款图形管理界面,一分钟内配置 10 个 WireGuard 客户端不是梦
基于 WireGuard 和 OpenVPN 的混合云基础架构建设
可以找一台能联网的 centos7 测试一下这个端口,如果没有 nc 工具可以yum install nc安装下。:
米开朗基杨
2021/04/23
8.1K1
基于 WireGuard 和 OpenVPN 的混合云基础架构建设
wireguard
Wireguard服务器/客户端配置 1. C/S wg安装 $ sudo yum install yum-utils epel-release $ sudo yum-config-manager --setopt=centosplus.includepkgs=kernel-plus --enablerepo=centosplus --save $ sudo sed -e 's/^DEFAULTKERNEL=kernel$/DEFAULTKERNEL=kernel-plus/' -i /etc/syscon
墨文
2021/06/09
1.9K2
搭建WireGuard
4. 配置 WireGuard:在 VPS 主机上创建一个 WireGuard 配置文件 wg0.conf,将以下配置信息添加到该文件中:
用户8658949
2023/03/04
4K0
Set up WireGuard Server in OpenWRT
By HKL, on Sunday 2023-08-13 21:12, tagged: 🏷️Networking 🏷️Operating
hiplon
2023/10/18
6970
Set up WireGuard Server in OpenWRT
什么?WireGuard 可以让躲在 NAT 后面的客户端之间直连了??
WireGuard 是由 Jason A. Donenfeld 等人创建的下一代开源 VPN 协议,旨在解决许多困扰 IPSec/IKEv2、OpenVPN 或 L2TP 等其他 VPN 协议的问题。2020 年 1 月 29 日,WireGuard 正式合并进入 Linux 5.6 内核主线。
米开朗基杨
2021/02/25
19.8K0
什么?WireGuard 可以让躲在 NAT 后面的客户端之间直连了??
WireGuard VPN Management Web Ui
之前写了一篇文章,介绍除了Openvpn之外的另外一个简单的组网软件wireguard.配置相当简单,有兴趣的可以通过下面的链接看一下:
公众号: 云原生生态圈
2021/01/13
8.6K0
WireGuard VPN Management Web Ui
彻底理解 WireGuard 的路由策略
很久以前,我们只需要在 Linux 终端中输入 route -n(后来演变出了 ip route,也就是 iproute2 提供的命令),就可以知晓系统中所有数据包的走向,但是,大人,时代变了!
米开朗基杨
2022/11/07
7.5K0
彻底理解 WireGuard 的路由策略
OpenWRT搭建WireGuard服务器
By HKL, on Friday 2019-11-29 15:25, tagged: 🏷️Networking 🏷️Operating
hiplon
2023/10/18
4.7K0
OpenWRT搭建WireGuard服务器
Fedora33下搭建WireGuard虚拟专用网
WireGuard 是一个易于配置、快速且安全的开源 Virtual Private Network,它利用了最新的加密技术。目的是提供一种更快、更简单、更精简的通用 Virtual Private Network,它可以轻松地在树莓派这类低端设备到高端服务器上部署。
yuanfan2012
2020/12/31
2.4K0
Fedora33下搭建WireGuard虚拟专用网
【运维】Wireguard+OpenVPN解决跨地区VPN的连接稳定性问题
UDP在实际使用上可能会被QOS限速,但是在长距离、高延迟的VPN环境中还是可以发挥不错的效果,不容易出现TCP经常断连的情况。
正汰
2024/01/16
4.4K0
【运维】Wireguard+OpenVPN解决跨地区VPN的连接稳定性问题
记录 | 通过WireGuard实现异地组网
由于我管理着几台不同地域,不同网络,网络类型并不相同( NAT端口转发 / 公网独立IP )的云服务器,以及我需要将家中的服务器的服务映射至公网以供其他人进行访问,所以我需要一个异地组网方案解决该问题。
Leo Deng
2024/07/22
9472
WireGuard 系列文章(二):WireGuard 简介 - 快速、现代、安全的 V** 隧道
WireGuard® 是一个非常简单,快速和现代的 V**,它利用了最先进的 密码学[2]。它旨在比 IPsec更快[3],更简单[4],更精简,更有用,同时避免巨大的头痛。它比 OpenV** 的性能要高得多。WireGuard 被设计为一个通用 V**,用于在嵌入式接口和超级计算机上运行,适用于许多不同的情况。它最初是为 Linux 内核发布的,现在是跨平台(Windows,macOS,BSD,iOS,Android)并且可以广泛部署。它目前正在进行大量开发,但它已经被认为是业内最安全,最易于使用和最简单的 V** 解决方案。
东风微鸣
2022/04/22
10.4K0
WireGuard 系列文章(二):WireGuard 简介 - 快速、现代、安全的 V** 隧道
公网部署 k3s 集群方法总结
Kubernetes 在当下的火热程度不必多言,但由于其体量较大,自身组建就会占用不少资源,适合大规模部署。k3s 是一个轻量的 Kubernetes 实现,通过了官方认证,在占用极低资源的情况下可以提供大部分功能,个人轻量服务器、树莓派之类资源有限的情况下显得特别好用。
宋天伦
2023/10/20
1.7K0
推荐阅读
相关推荐
WireGuard 系列文章(九):基于 K3S+WireGuard+Kilo 搭建跨多云的统一 K8S 集群
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档