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
