websocket压测过程
目录
测试资源
- 1台被压测机器
- centos版本信息参考线上服务器
- 双核4G
- 业务服务部署:ws服务(golang实现websocket的一个服务)、redis服务(本地6379端口)
- 监测服务:prometheus、grafana、cacti。需要监测服务器资源使用情况、需要监测go服务使用情况
- 系统配置调整:ulimit
- 2台压力机器
- 双核2G内存
- ubuntu18及以上。
- 服务部署:最新jdk、jmeter服务安装与配置(slave)
- 1台压力控制机
- 单核1G内存,连接操作顺畅即可
- 服务部署:最新jdk、jmeter服务安装与配置(master)
- 其他
- 竞价实例
- 4台机器在同一个局域网内
- 关闭防火墙
测试环境准备
系统配置调整
-
ulimit调整系统文件
临时调整了ulimit为50000,默认是1024,会影响数据库、redis等服务连接数
修改/etc/security/limits.conf文件,在文件中添加如下行,修改系统对所有用户的软限制(软限制是指限制用户同时打开的文件数目,硬限制是指系统根据硬件资源(主要指内存)计算出来的最多可打开的文件数目)
* soft nofile 60000 * hard nofile 60000
redis
yum install redis
定期删除redis所有数据:
flushall
定制ws服务
- 调整token机制,避免泄露
- 增加控制端与被控制端连接统计,提供给prometheus采集
分支:jm-loadtest
配置文件:config.cfg(参考测试环境)
jmeter服务
-
jdk
master控制机、slave压力机需要使用相同版本的jdk。
-
jmeter
master控制机、slave压力机安装相同版本的jmeter
-
下载
-
解压到指定位置
比如unix可以尝试放在/usr/local/jmeter下
windows环境,解压可以执行GUI界面即可。
-
unix环境配置全局环境变量
vim /etc/profile
export JMETER=/usr/local/jmeter export PATH=$JMETER/bin:$PATH source /etc/profile
-
-
配置master控制机
修改master控制机bin/jmeter.properties配置,添加需要控制的远程压力机:
remote_hosts=192.168.232.128:1099
不启用ssl:
server.rmi.ssl.disable=true
修改bin/system.properties配置,用于告知slave回传数据给master的地址:
java.rmi.server.hostname=192.168.232.131
-
配置slave压力机
用于与master的数据传输,比如master发送脚本到slave,salve发送结果给master,修改bin/jmeter.properties配置:
# RMI port to be used by the server (must start rmiregistry with same port) server_port=1099
不启用ssl
server.rmi.ssl.disable=true
测试数据
- 10万个phone用户数据
- 20万个web用户数据,2个web用户与1个phone用户关联,也就是1个控制端对应2个被控制端
暂时提供csv的参数化方式,没有使用JDBC的方式直接数据库。需要将参数配置数据同时上传到压力机jmeter-server启动的目录下(注意相对路径)
附:测试数据生成存储过程
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,"9ong")),"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`;
服务启动
-
启动ws服务
./wssrv >>/var/log/wssrv.log &
-
启动压力机jmeter-server服务
//hostname为本机ip jmeter-server -Djava.rmi.server.hostname=192.168.232.xxx
-
jmeter控制机压测
注意:需要先启动压力机jmeter-server后,开始压测时才执行
//linux jmeter -n -t ws-plan.jmx -r -l ws-plan.jtl
//windows .\jmeter.bat -n -t E:\jmeter\ws-phones-connect.jmx -r -l E:\jmeter\jtl\ws-phones-connect-1659.jtl .\jmeter.bat -n -t E:\jmeter\ws-web-phone.jmx -r -l E:\jmeter\jtl\ws-web-phone-1535.jtl
注意:jmeter如果没有配置全局环境的话,要在jmeter/bin目录下执行命令行
测试计划
小数据场景
假设:总控制端数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)
在保持连接压测的基础上,压测时,主动关闭压测,即异常中断所有连接,观察后续服务器状态,有没有恢复到压测前的状态
-
并发非法重连。模拟客户端使用旧连接重试处理不当时,导致疯狂重连
-
并发关闭连接
压测前状态恢复
- 等服务器负载稳定
- 小数据服务重启保证初始化状态一致
- 清空redis
操作步骤
- 执行jmx,注意jtl文件命名
- 观察gfafana
- excel记录开始和结束时间
- 导出jtl,导入jmeter GUI查看
- grafana截图最近一段时间曲线图
- 等待服务恢复
跟踪测试问题
1、redis 连接too many open file
临时调整了ulimit为10000,默认是1024,会影响数据库、redis等服务连接数
修改/etc/security/limits.conf文件,在文件中添加如下行,修改系统对所有用户的软限制(软限制是指限制用户同时打开的文件数目,硬限制是指系统根据硬件资源(主要指内存)计算出来的最多可打开的文件数目)
* soft nofile 60000
* hard nofile 60000
2、本次虚拟机初步压测
两台虚拟机作为压测机,宿主机windows作为控制机,组成一个局域网。
另外其中一台虚拟机提供小数据服务。
虚拟机配置:4G内存、双核
初步压测被控端并发连接,并发策略是两台机器分别同时并发10000个用户(thread),发起小数据服务连接,并在连接成功后10s,发送一次ping,再等5s主动关闭连接,初步得到一个大概的数据:
```
label samples average median 90%line 95%line 99%line min Max Error% Throughput Received Sent
new connection 20000 2990 19 6430 22159 31231 0 32106 0.05465 211.8846076426778 44.23314656588022 1.1930303537943237
ping and pong 20000 294 0 0 1 19834 0 25061 0.04095 1.2234507086371877E-5 1.3031590002153336E-6 8.03684053638119E-8
close connection 20000 3527 1828 8270 11247 21851 0 24029 0.30585 1.2234507048936118E-5 3.3174152609449244E-8 3.5591722266497074E-7
close connection-0 14866 953 0 2861 3771 7555 0 19605 0.0 160.38753668220266 17.848036726706802 0.0
close connection-1 180 0 0 0 0 0 0 20 0.0 3.274989993086132 0.36459849532404204 0.0
close connection-2 38 1 0 0 0 43 0 43 0.0 21.952628538417102 2.443944974003466 0.0
TOTAL 75084 2003 1 6322 8688 29668 0 32106 0.10693356773746737 4.593078636311597E-5 4.9172383523639865E-6 5.051728321696359E-7
```
(可读性强点可以再导入压测结果文件jtl:jmeter\jtl\ws-phones-connect-1659.jtl)
3、并发10000连接时出现WebSocket I/O error: Read timed out
Thread Name:172.16.0.16:1099-phone threads group 1-1002
Sample Start:2021-10-25 13:32:54 CST
Load time:6004
Connect Time:0
Latency:0
Size in bytes:0
Sent bytes:0
Headers size in bytes:0
Body size in bytes:0
Sample Count:1
Error Count:1
Data type ("text"|"bin"|""):
Response code:Websocket I/O error
Response message:WebSocket I/O error: Read timed out
SampleResult fields:
ContentType:
DataEncoding: null
之前默认连接时,如果超过6000ms没有响应就认为连接失败,暂时调整为10000ms,当然在被压测云服务器这么快就发生了这个处理不过来的连接响应,有点意外,本地虚拟机在10000并发时,还是很顺畅的。
解决:
结果发现:是因为并发地址是被压机器的外网ip,可能因为云外网环境线路等原因导致这个请求链较长
【jmeter知识】03_jmeter接口报Read timed out +ng日志499分析 - chooperman - 博客园
4、压力机并发限制,内存不足问题
在一次每台并发20000的场景时,压力机出现了错误,
Starting the test on host 172.16.0.16:1099 @ Mon Oct 25 16:05:22 CST 2021 (1635149122254)
[9495.706s][warning][os,thread] Failed to start thread - pthread_create failed (EAGAIN) for attributes: stacksize: 1024k, guardsize: 0k, detached.
Uncaught Exception java.lang.OutOfMemoryError: unable to create native thread: possibly out of memory or process/resource limits reached in thread Thread[StandardJMeterEngine,5,RMI Runtime]. See log file for details.
解决:
编辑jmeter.bat或jmeter(shell文件),调整最大可使用内存Xmx为2g,Xms表示初始化内存,由于压力机是4g内存,暂时考虑官方建议不超过物理内存的一半:
\# This is the base heap size -- you may increase or decrease it to fit your
\# system's memory availability:
\#: "${HEAP:="-Xms1g -Xmx1g -XX:MaxMetaspaceSize=256m"}"
: "${HEAP:="-Xms1g -Xmx2g -XX:MaxMetaspaceSize=256m"}"
以上方案失败了
解决2:
官方这么说的:
To set those variables permanently, you can place them in a file called setenv.sh in the bin directory. This file will be sourced when running JMeter by calling the jmeter script
所以我们新建文件jmeter/bin/setenv.sh:
export HEAP="-Xms2g -Xmx2g -XX:MaxMetaspaceSize=512m"
注意:setenc.sh文件,因为md文档原因,缺失了shell文件头,需要自己补充
Apache JMeter - User’s Manual: Getting Started
解决3:
由于已经不是堆的问题,超出RAM的问题,只能应加机器,或提升内存。
5、jtl文件太大,在linux上生成报告问题
目前最新的jdk17不支持jmeter在linux上生成报告。
需要降级到jdk16