websocket压测计划
目录
目的
产品中有个服务是websocket的服务,我们需要了解websocket服务的健壮性和高并发能力。
计划
- 本地环境下websocket demo
- 基础开关ws、发送消息
- 参数化配置
- 补充周期循环逻辑控制器
- 关闭连接demo
- 工具关闭,ws是正常发送关闭还是异常,等服务端心跳机制检查关闭
- 补充断言
- 支持命令行动态设置压力
- linux环境下部署
- jmeter linux cli版、websocket插件jar包、
- 压力机系统参数调整
- linux环境jmeter脚本测试
- 上传jmx、参数化配置文件
- demo测试,能生成jtl结果文件
- 被测试websocket服务部署
- 调整默认心跳配置,方便测试,比如默认心跳调整为1分钟。暂时不调整
- 调整一些调用push,是直接返回,还是允许写入redis即可?直接写本地redis
- 修改token加密方式或盐值,避免意外泄露算法与盐值。
- 准备终端设备虚拟数据
- 准备并发场景jmx
- 分布式环境
- 服务器状态监测。zabbix、cacti、pprof、prometheus (负载、cpu、内存、连接等资源)
- cacti服务器资源监测
- prometheus go服务资源监测
- pprof
工具
-
jmeter
Apache JMeter - Apache JMeter™
- 支持多轻量组件
- 支持多线程
- 支持GUI与non GUI方式
- 支持缓存和离线分析和回放测试结果
- 数据分析与可视化插件
- 支持动态输入
- 支持代理
- 支持分布式
- 支持windows与linux环境,通过配置文件跨平台测试
-
tsung
- 支持多线程
- 没有GUI,编写配置文件
- Erlang开发,支持集群大并发
- 支持http、soap、mysql、xmpp、websocket等
- 环境自然分布
- 支持代理
- 支持数据采集与分析,在线查看
-
其他
Locust - A modern load testing framework
测试资源
- 1台被压测机器
- centos版本信息参考线上服务器
- 双核4G
- 业务服务部署:小数据服务、redis服务(本地6379端口)
- 监测服务:prometheus、grafana、cacti。需要监测服务器资源使用情况、需要监测go服务使用情况
- 系统配置调整:ulimit
- 2台压力机器
- 双核2G内存
- ubuntu18及以上。方便的话。
- 服务部署:最新jdk、jmeter服务安装与配置(slave)
- 1台压力控制机
- 单核1G内存,连接操作顺畅即可
- 服务部署:最新jdk、jmeter服务安装与配置(master)
- 其他
- 竞价实例
- 4台机器在同一个局域网内
- 关闭防火墙
系统环境准备
- windows环境安装与websocket插件jar包
- dataforward压测计划demo
- linux环境安装与websocket插件jar包
- 分布式环境(详见分布式环境)
- 压力测试瓶颈在带宽上面,需要保证压力测试机的带宽要比被测服务器的带宽高,否则压力上不去。
- 需要保证jmeter的server和agent都在一个网络中,且在多网卡环境需要保证启动的网卡都在一个网段。
- 需要保证jmeter的server和agent之间的时间同步。
- 关闭防火墙。
- dataforward服务部署
jmeter安装
-
下载
-
解压到指定位置
比如unix可以尝试放在/usr/local/jmeter下
windows环境,解压可以执行GUI界面即可。
-
unix环境配置全局环境变量
export JMETER=/usr/local/jmeter export PATH=$JMETER/bin:$PATH
分布式环境配置
[图片来源CSDN]
master 与 slave机器都需要相同版本的jdk与jmeter安装。
- master
-
master 作为压力机集群调度
-
添加压力机slave/agent
修改master机器bin/jmeter.properties配置中的
remote_hosts=remote_hosts=192.168.232.128:1099
-
不启用ssl
server.rmi.ssl.disable=true
-
- slave
-
slave作为压力机
-
设置jmeter服务端口
用于与master的数据传输,比如master发送脚本到slave,salve发送结果给master
# RMI port to be used by the server (must start rmiregistry with same port) server_port=1099
-
不启用ssl
server.rmi.ssl.disable=true
-
启动jemeter服务
jmeter-server -Djava.rmi.server.hostname=192.168.232.128
范例
jm@ubuntu18:/usr/local/jmeter/bin$ jmeter-server -Djava.rmi.server.hostname=192.168.232.128 Created remote object: UnicastServerRef2 [liveRef: [endpoint:[192.168.232.128:37513](local),objID:[-11c47cdd:17c8792aa10:-7fff, 6317240269053942982]]]
-
测试数据
use jmtest;
-- 删除过程
DROP PROCEDURE test_web_insert;
-- 定义存储过程
DELIMITER $$
CREATE PROCEDURE test_web_insert(max_num INT)
BEGIN
DECLARE i INT DEFAULT 0;
DECLARE j INT DEFAULT 0;
DECLARE _phone_id VARCHAR(32) DEFAULT '';
DECLARE _web_id VARCHAR(32) DEFAULT '';
DECLARE _token VARCHAR(32) DEFAULT '';
DECLARE _instance_id VARCHAR(15) DEFAULT '';
SET autocommit = 0;
REPEAT
SET _phone_id = MD5(UUID_SHORT());
SET _instance_id = concat(substring(_phone_id,1,7),"_",substring(_phone_id,10,7));
SET _token = MD5(CONCAT(MD5(CONCAT(_phone_id,"airdroid")),"loadtest"));
SET j=0;
SET i = i + 1;
INSERT INTO `phone_data`(phone_device_id,token,instance_id) VALUES(_phone_id,_token,_instance_id);
WHILE j<2 DO
SET _web_id = MD5(UUID_SHORT());
INSERT INTO `web_data`(phone_device_id,web_device_id,token,instance_id) VALUES(_phone_id,_web_id,_token,_instance_id);
SET j=j+1;
END WHILE;
UNTIL i = max_num
END REPEAT;
COMMIT;
END $$
-- 删除
DELIMITER ;
--- 调用过程
CALL test_web_insert(2);
-- 重置表
TRUNCATE TABLE jmtest.`web_data`;
TRUNCATE TABLE jmtest.`phone_data`;
场景设计
场景
-
场景
- 被控端连接、心跳
- 控制端连接、心跳
- 控制端转发消息到被控端
-
可能瓶颈点
- 互斥锁
- 读写锁
- websocket管理变量占用内存
- 计算token
- 定时器
-
差异
- ssl
- origin 设置或屏蔽
小数据场景
假设:总控制端数M,总被控制端数N(N是M的2倍)
注意:每次压测前都需要等服务器负载稳定后,且压测服务重启保证初始化状态一样。
-
记录服务器初始化状态
-
并发连接
-
1、被控端并发连接(ws-phones-connect)
脚本:1秒内1000并发,各发一次ping,1至5s后关闭
-
2、被控制端并发连接,保持连接,即维持心跳一段时间(ws-phones-connect-ping)
在步骤1的基础上出现连接失败临界并发点时,再考虑最大可成功连接的并发数下,维持心跳10次(甚至更多),每次10至30s随机发送ping,之后1至5s随机关闭连接
-
3、被控端与控制端混合并发连接
直接并发
-
4、被控端与控制端混合并发,并保持连接
在步骤3的基础上找到临界并发点,参考2
-
5、模拟远程控制场景(ws-web-phone)
控制端与被控端一对并行并发连接,模拟远程控制,10至30s随机发ping,10至30次后,控制端在随机ping中穿插转发控制消息,在ping周期结束1至5s之后关闭连接
-
-
保持连接(ws-web-phone-most)
阶梯性连接(5000web+5000phone)/10s,直到连接大量失败,找到可保持的连接数临界点。维持心跳(10至30s) * 60,控制端 40% * 60 次概率性转发消息,每个连接在60次心跳之后1至5s正常关闭连接
-
并发连接异常断开(ws-web-phone-most)
在保持连接压测的基础上,压测时,主动关闭压测,即异常中断所有连接,观察后续服务器状态,有没有恢复到压测前的状态
-
并发非法重连。模拟客户端使用旧连接重试处理不当时,导致疯狂重连
-
并发关闭连接
分布式压测
-
准备jmx脚本(可以在windows gui环境debug准备)
-
准备测试数据,详见下一节 测试数据
- 需要将测试数据手动放入对应压力机linux环境下
-
linux环境分布式测试
#执行全部远程压力机 jmeter -n -t ws-plan.jmx -r -l ws-plan.jtl #执行指定远程压力机 jmeter -n -t ws-plan.jmx -R 192.168.232.132 -l ws-plan.jtl
-n 这指定 JMeter 以 cli 模式运行 -t [包含测试计划的 JMX 文件的名称]。 -l [将样本结果记录到的 JTL 文件的名称]。 -j [JMeter 运行日志文件的名称]。 -r 在 JMeter 属性“ remote_hosts ”指定的服务器中运行测试,也在-r后面指定要执行的slave压力机ip -R [远程服务器列表] 在指定的远程服务器上运行测试 -G [CSV 文件的路径] 仅生成报告仪表板 -e 负载测试后生成报告仪表板 -o 负载测试后生成报告仪表板的输出文件夹。文件夹不得存在或为空 该脚本还允许您指定可选的防火墙/代理服务器信息: -H [代理服务器主机名或 IP 地址] -P [代理服务器端口]
范例:
jm@ubuntu18:~/jmeter$ jmeter -n -t ws-plan.jmx -r -l ws-plan-1019.jtl Creating summariser <summary> Created the tree successfully using ws-plan.jmx Configuring remote engine: 192.168.232.131:1099 Configuring remote engine: 192.168.232.132:1099 Starting distributed test with remote engines: [192.168.232.131:1099, 192.168.232.132:1099] @ Tue Oct 19 08:28:03 UTC 2021 (1634632083948) Remote engines have been started:[192.168.232.131:1099, 192.168.232.132:1099] Waiting for possible Shutdown/StopTestNow/HeapDump/ThreadDump message on port 4445 summary + 1 in 00:00:00 = 2.5/s Avg: 7 Min: 7 Max: 7 Err: 0 (0.00%) Active: 1 Started: 2 Finished: 1 summary + 19 in 00:00:46 = 0.4/s Avg: 0 Min: 0 Max: 2 Err: 0 (0.00%) Active: 0 Started: 7 Finished: 7 summary = 20 in 00:00:47 = 0.4/s Avg: 0 Min: 0 Max: 7 Err: 0 (0.00%)
默认会在当前目录下.log生成日志文件
注意:参数配置化的数据文件也需要能够被加载,如果有什么问题,可以查看日志,确认是出现什么异常错误,一般如果在windows环境下能跑的,在linux环境下也不会有问题,有问题一般都是缺少插件包、文件路径不对等缺失,补充上即可。
-
导出jtl结果文件到GUI展示
如何打开jtl数据展示,详见参考
-
生成可视化报告
-
jmeter GUI生成报告
tools->generate HTML report
指定对应的jtl文件,指定jmeter安装目录下bin/user.property文件,指定要生成的目的目录(要求空目录,可以新建)
-
命令执行
jmeter -g xxx.jtl -o [report dir,empty dir]
如果大并发压测的话,jtl文件可能会上百M甚至G,可以在linux上直接生成报告,但要注意jdk17目前不兼容在linux上生成报告,需要降级到jdk16。
-
可视化
-
参考
Apache JMeter - User’s Manual: Remote (Distributed) Testing