目录

目的

产品中有个服务是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

工具

测试资源

  • 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安装

  • 下载

    Apache JMeter - Download Apache 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。

    • 可视化

      JMeter命令行执行+生成HTML报告 - 解读参考

参考

Apache JMeter - User’s Manual: Remote (Distributed) Testing

Apache JMeter - User’s Manual: Getting Started - CLIMode

Linux下使用Jmeter压测 - 掘金