• 自研长链接压测概览


    项目背景

    公司的长链接服务器,有以下等缺点:

    ● 触达率很低

    ● 没有点对点推送能力

    ● 排查问题困难

    ● 只支持m2,不支持mid

    而我们商业化的项目众多,且非常依赖长链接服务,因此自研一套长连接系统提供服务,对标公司长链接服务。

    在这里插入图片描述

    压测分析

    1 压测目的

    新系统上线,确定系统的相关性能指标、性能瓶颈、服务可用性、服务稳定性等

    2 压测场景

    ①新系统上线

    准确探知系统能力,防止系统上线被流量打垮

    ②性能探测

    探测系统中的性能瓶颈点,进行针对性优化

    ③容量规划

    对站点进行精细化的容量规划,为系统扩容,性能优化提供数据参考,节省成本投入,提高资源利用率

    3 压测策略

    ①基准测试

    作为基准,在后续有框架变动/代码变动/业务逻辑变动时,进行对比

    ②负载测试

    确定系统的最佳负载和最大负载,合理的进行资源申请

    ③压力测试

    确定系统的极限指标

    ④稳定性测试

    在略低于最佳负载值下,持续压测5~7d

    4 发压策略

    ①线上单机压测时,使用1台发压机;超过1000TPS时,使用分布式发压

    ②集群压测时,使用多台机器进行分布式压测

    压测指标预估

    备注

    本次RT时间 以TP95 为标准

    因新业务上线,无真实流量,无法确定峰值QPS,需要进行TPS估算

    TPS估算

    估算1

    按照10亿用户,按照八二原则,计算TPS需要到~~46300,有20台机器,单机达到2500即可。

    估算2

    初次放量,按照100w用户 20台机器估算,根据八二原则,单机TPS均值:10 qps,峰值:50 qps。

    01 业务指标

    图片

    02 资源指标

    ● CPU使用率(时间):

    不高于75%-85%

    ● 内存 RAM(大小)使用率:

    不高于80%

    观察内存是否有尖刺或泄露

    ● 磁盘I/O(速率) :

    不高于90%

    ● 网络I/O(速率):

    不高于80%

    03 中间件监控指标

    防火墙

    ● 无防火墙

    ngnix

    ● 带宽

    ● 配置是否正确

    redis

    ● 缓存穿透、击穿、雪崩

    mysql – 本次压测不涉及

    ● 慢查询

    ● 线程阻塞

    ● 死锁

    ● 无索引导致全表查询

    04 使用的第三方业务

    ● 不涉及第三方

    压测流程

    1. 需求分析

    熟悉需求、获取性能需求指标
    ①明确被测系统 及 压测场景

    ②明确测试内容

    ③明确测试策略

    ④明确测试指标

    2. 压测方案制定与评审

    综合以上一~四的内容,加上压测机器信息,压测周知,编写压测方案,编写完成后召集相关人员进行压测方案评审,方案内容大纲如下:

    图片

    备注:当服务器涉及到容器云和HULK时,需要提前与相关方确认,提供压测的TPS,确认压测的执行时间,防止影响其他业务线。

    3. 测试用例设计与压测脚本编写

    本次涉及http接口和websocket接口

    Ⅰ. 压测组件选择

    根据压测涉及接口 及 模拟业务场景的需要,进行最小化的组件选择。

    ● 测试计划

    ● 线程组
    压测进行梯度压测,标准线程组需要频繁更改CLI命令,因此直接使用了并发线程组。

    并发线程组配置采用参数化方式,在Linux / Docker中执行时,可以直接使用CLI传入并发数,省去频繁更改脚本的麻烦。

    Ramp Up Time 与 Ramp Steps Count 也需要动态调整,在并发量较大时,适当调大避免曲线不正常波动带来的不准确性。

    ●配置元件
    用户自定义的变量

    采用该组件记录全局参数
    HTTP信息头管理器
    用于请求接口添加Header字段

    ●前置处理器
    用户参数组件
    模拟海量不同用户,利用RadomString 函数,构造m2 和 mid 。

    m2   ${__RandomString(44,0123456789qwertyuiopasdfghjklzxcvbnm,)}
    mid  ${__RandomString(32,0123456789qwertyuiopasdfghjklzxcvbnm,)}
    
    • 1
    • 2

    该组件一定要放入并发线程组中,才能模拟每次发起请求是不同的用户
    BeanShell 前置处理器
    处理HTTP接口中字段,按照指定算法进行加密,密文作为Websocker的Header参数

    ● 定时器
    模拟业务逻辑,构造时间间隔

    ● 取样器
    HTTP取样器
    WebSocket 取样器
    WebSocket Open Connection
    WebSocket request-response Sampler

    ● 后置处理器
    JSON提取器
    用于提取指定字段,用于传递下一接口或者做接口断言
    正则表达式提取器
    用于提取响应字段中的内容 url 和 port

    ● 断言
    响应断言
    用于校验接口请求是否成功
    Json断言
    用于校验响应中业务逻辑是否符合预期

    ● 监听器
    后端监听器
    JMeter抓取数据,传递给influxdb存储,使用grafana展示

    ● 其他组件(调试脚本时添加,真正压测时要去掉)
    查看结果树
    调试取样器
    汇总报告(主要关注方差指标)
    聚合报告
    jp@gc - Active Threads Over Time

    jp@gc - Transactions per Second

    jp@gc - Response Times Over Time

    Ⅱ. 压测脚本编写

    脚本先在GUL模式下运行通过,再进行场景关联、CLI参数化等

    图片

    Ⅲ. 压测执行

    ①搭建压测环境
    根据压测TPS不同,选择不同的压测执行环境
    ②执行测试脚本
    根据压测环境的不同,压测执行方式也是不同的
    windows GUI 压测执行
    windows 分布式压测执行
    windows CLI 压测执行
    Linux CLI 压测执行
    基于Dokcer的分布式压测执行
    ③测试结果记录
    最后的压测报告生成,以及后续做对比基准使用

    Ⅳ. 问题分析和调优

    由于本次发现的几个问题均与性能瓶颈无关,这里就不列举了。

    Ⅴ. 压测报告输出

    性能测试报告是性能测试的里程碑,通过报告能展示出性能测试的最终成果,展示系统性能是否符合需求,是否有性能隐患。

    注意包含以下几方面:

    ①压测背景、目的、目标
    ②参与人、时间跨度
    ③施压环境 及 施压工具
    ④数据构造方法
    ⑤压测策略
    ⑥压测执行过程记录
    ⑦记录定位瓶颈和调优过程

    压测执行的几种方式

    具体使用哪种方式,是根据压测TPS和申请到的资源决定的。
    几种压测方式的搭建过程 以及 优缺点,会在拆解的详细章节中讲述。
    本章节概览只展示下几种压测执行方式的运行方式和运行结果展示。

    1 windows GUI 压测执行

    ● JMeter官方提示:不要使用GUI模式进行负载测试!只有在测试调试或者测试用例设定或者生成的时候才用GUI模式。
    ● GUI模式带来性能损耗,不适合500以上并发的压测执行
    ● 在windows JMeter中直接执行时,需要配置上以下组件,以便观察结果
    查看结果树
    调试取样器
    汇总报告
    聚合报告
    jp@gc - Active Threads Over Time

    jp@gc - Transactions per Second

    jp@gc - Response Times Over Time
    图片

    备注:JMeter本身的问题导致结束时无法优雅关闭,忽略最后的错误即可。

    2 windows 分布式压测执行 - GUI方式

    ①原理

    Jmeter分布式测试时,客户端机器(window系统或者Linux服务器)作为一个控制器Master,控制多台slave机器的操作。

    图片

    ②配置

    具体的master 和 slave 的配置,会在分篇章中详细描述。不影响理解主线流程。
    ③执行

    在jmeter GUI 中可以通过如下方式调度远程slave 机器执行压测任务

    ● 菜单项-运行-远程启动,指定运行机器

    ● 菜单项-运行-远程启动所有,会按照remote host中配置的负载机执行压测。

    图片

    ④查看执行结果

    图片

    ⑤清理

    运行结束后需要手动去停止每个slave节点的进程

    3 windows CLI 压测执行

    CLI 相关参数:

    -n 表示使用非GUI的方式运行
    -t 表示指定jmeter的测试脚本
    -l 表示生成指定的报告文件
    -e 表示生成html报告
    -o html报告输出的路径
    -J 相关的参数,需要结合测试脚本中定义的参数化变量使用的。

    ①本机执行脚本

    jmeter -n -t cljzyycone.jmx -l jtl/x.jtl -e -o report/
    -JthreadNum=10 -JrampTime=20 -JstepTime=20 -Jduration=10
    
    • 1
    • 2

    查看控制台和生成的报告-本机执行
    图片

    ②远程调度执行脚本
    master 调度 slave 执行,需要加上 -r 或者 -R 选项

    调度全部slave 使用 -r

    jmeter -n -t cljzyycone.jmx -r -l jtl/x.jtl -e -o report/
    -GthreadNum=10 -GrampTime=20 -GstepTime=20 -Gduration=10
    
    • 1
    • 2

    调度指定slave 使用 -R host的形式

    jmeter -n -t cljzyycone.jmx -R 10.19.1.219 -l jtl/x.jtl -e -o report/
    -GthreadNum=10 -GrampTime=20 -GstepTime=20 -Gduration=5
    
    • 1
    • 2

    查看控制台-远程调度执
    图片

    4 windows CLI 压测执行

    ①Linux 上安装JMeter①. Linux 上安装JMeter
    ②创建压测目录,存放压测脚本和测试报告
    ③docker-compose up 启动监控系统的几个service
    ④执行压测脚本

    #宿主机运行
    jmeter -n -t cljzyycone.jmx -l jtl/cljyc.jtl -e -o report \
    -JthreadNum=1000 -JrampTime=10 -JstepTime=20 -Jduration=10
    
    • 1
    • 2
    • 3

    5 windows CLI 压测执行

    图片

    备注:如上的图形是有问题的,已经提交开发查看

    6 基于Dokcer实现 JMeter的分布式压测执行

    当压测目标TPS较高时,需要部署多台linux服务器,但分布式压测要求:

    ● JMeter压测要求每台机器的基础环境都要相同

    每台机器都要先安装相同的java环境
    再安装相同版本的JMeter
    配置相同JMeter 插件
    更改相同的配置文件(slave要改四个配置文件)

    ● 每台slave都需要单独的安装配置,如果有变动,需要按个操作一遍
    ● 每台slave 需要打开指定的端口并运行JMeter服务器,准备就绪并等待主服务器发送指令。
    ● 数据驱动文件每台机器都要上传一份,且要保证路径相同,有变动的话需要全部重新上传一遍
    ● 执行压测时,进行统一调度比较繁琐(每台机器都要指定端口号)

    使用docker可以很好的解决以上问题。

    概述实现过程

    1. 创建基于centos7的java8 Dockerfile,作为jmeter的父层级
      official的java8镜像是基于dibian系统,在公司即使配置了国内源,仍然下载漫长又容易失败。
      因此定制一个基于centos7的 java8镜像,同时集成进一些常用包

    2. 创建JMeter相关的Dockerfile,编写一些build命令、run命令、exec命令的脚本,最终启动 master 容器和 slave 容器。(后续的分章节再介绍这些脚本内容及使用方法)

    图片

    1. 创建master 和 slave镜像

    以创建slave镜像为例

    ①编写Dockerfile-slave

    FROM handan0723/jmeter-base:v2
    MAINTAINER jmeter-docker
    EXPOSE 1099 50000
    ENTRYPOINT $JMETER_HOME/bin/jmeter-server \
    -Dserver.rmi.ssl.disable=true \
    -Dserver.rmi.localport=50000 \
    -Dserver_port=1099
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    ②构建slave镜像

    sh build.sh slave v2
    
    • 1

    build.sh:

    #!/bin/bash
    
    JMETER_VERSION=${JMETER_VERSION:-"5.4.3"}
    IMAGE_TIMEZONE=${IMAGE_TIMEZONE:-"Asia/Shanghai"}
    
    build_type=$1
    build_tag=$2
    
    docker build \
    --build-arg JMETER_VERSION=${JMETER_VERSION} \
    --build-arg TZ=${IMAGE_TIMEZONE} \
    -f Dockerfile-$build_type \
    -t jmeter-$build_type:$build_tag .
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    涉及的镜像均已上传docker hub,按需使用

    [root@localhost jmeter-docker]# docker search handan0723
    NAME                       DESCRIPTION                              STARS     OFFICIAL   AUTOMATED
    handan0723/jmeter-base     v2版本基于handan0723 / jdk8-centos:v4,V1基…   0                    
    handan0723/jmeter-master   v2                                       0                    
    handan0723/jmeter-slave    v2                                       0                    
    handan0723/jdk8-centos     v1-v3对应dockerfile 是使用jdk安装的,v4使用y…       0     
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    1. 生成容器
    sh runmaster.sh 1 60000
    sh runslave.sh 1 1100 1099 50000 50000
    sh runslave.sh 2 1101 1099 50001 50000
    
    • 1
    • 2
    • 3

    备注:
    每个slave生成容器时,要更换宿主机开放给容器的端口,如50000,50001递增

    slave容器数据卷可以只保留log目录和testdata目录,其他非必须。log目录用于存放日志,便于发生错误时进行问题定位;testdata用户存放数据驱动文件。

    [root@localhost jmeter-docker]# docker ps -a
    CONTAINER ID   IMAGE                    COMMAND                  CREATED              STATUS              PORTS                                                                                                                             NAMES
    f83d8339616f   jmeter-slave:v2          "/bin/sh -c '$JMETER…"   About a minute ago   Up About a minute   0.0.0.0:1101->1099/tcp, :::1101->1099/tcp, 0.0.0.0:50001->50000/tcp, :::50001->50000/tcp                                          jmeter-cljyc-slave-2
    3e8b366dedce   jmeter-slave:v2          "/bin/sh -c '$JMETER…"   About a minute ago   Up About a minute   0.0.0.0:50000->50000/tcp, :::50000->50000/tcp, 0.0.0.0:1100->1099/tcp, :::1100->1099/tcp                                          jmeter-cljyc-slave-1
    1ca4b3011cc1   prom/prometheus:latest   "/bin/prometheus --c…"   3 days ago           Up 3 days           0.0.0.0:9090->9090/tcp, :::9090->9090/tcp                                                                                         jk_prometheus
    1d838551945b   google/cadvisor:latest   "/usr/bin/cadvisor -…"   3 days ago           Up 3 days           8080/tcp, 0.0.0.0:8081->8081/tcp, :::8081->8081/tcp                                                                               jk_cadvisor
    31b549fc8611   grafana/grafana:latest   "/run.sh"                3 days ago           Up 3 days           0.0.0.0:3000->3000/tcp, :::3000->3000/tcp                                                                                         jk_grafana
    9ce0dc4eaf22   redis:latest             "docker-entrypoint.s…"   3 days ago           Up 3 days           0.0.0.0:6380->6379/tcp, :::6380->6379/tcp                                                                                         jk_redis
    e6d0f1331947   influxdb:1.8.10          "/entrypoint.sh infl…"   3 days ago           Up 3 days           0.0.0.0:8083->8083/tcp, :::8083->8083/tcp, 0.0.0.0:8086->8086/tcp, :::8086->8086/tcp, 0.0.0.0:8090->8090/tcp, :::8090->8090/tcp   jk_influxdb
    39e01d546376   jmeter-master:v2         "/bin/bash"              9 days ago           Up 9 hours          0.0.0.0:60000->60000/tcp, :::60000->60000/tcp                                                                                     jmeter-cljyc-master-1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    1. 查看容器ip

    此处IP查询结果,用户master cli命令行中控制slave使用

    docker inspect --format '{{ .Name }} => {{ .NetworkSettings.IPAddress }}' $( docker ps -a -q)
    
    • 1
    1. 进入master容器
    docker exec -it jmeter-cljyc-master-1 /bin/bash 
    
    • 1

    执行CLI命令,根据压测目标TPS,调整阶梯数值

    jmeter -n -t ./jmx/cljzyycone.jmx \
    -R 172.17.0.3:1099,172.17.0.4:1099 \
    -l ./jtl/cljyc.jtl \
    -e -o ./report \
    -j ./log/jmeter-master.log \
    -GthreadNum=10 -GrampTime=10 -GstepTime=10 -Gduration=50
    调度一台slave
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    图片

    调度2台slave

    图片

    对比下执行结果,我们脚本中要求的并发数10,不是两台共同完成10,而是每台都按照并发10去执行。因此可以实现加压的初始目的。

    图片

    监控系统

    在压测过程中,通过HTML报告可以查阅压测结果。但是只能在压测流程结束后,才能查看指标数据。无法观测执行过程中的异常波动,不具备实时性。如果使用Basic Graphs插件,因jmeter不擅长图形绘制,这样的组件极其耗损性能,影响压测执行及压测结果的准确性。

    因此需要使用监控系统,更及时准确的监控整个压测过程。

    具体的组件交互原理,环境搭建方式,配置过程,将会在单独的篇章中详细列出。概览只讲述组件构成,及使用方式。

    1. 监控系统组成

    jmeter:压测执行及数据采集

    InfluxDB:分布式时序、事件和指标数据库

    Prometheus:时序数据库

    Grafana:开源WEB可视化平台

    2. 实现原理

    采集 – 通过JMeter 中配置Backend Listener去实时采集数据

    存储 – 在 InfluxDB 中进行相关配置,存储采集来的数据

    展示 – 在 Grafana 中进行相关配置,存储采集来的数据存储 – 在 InfluxDB 中进行相关配置,存储采集来的数据存储 – 在 InfluxDB 中进行相关配置,存储采集来的数据存储 – 在 InfluxDB 中进行相关配置,存储采集来的数据存储 – 在 InfluxDB 中进行相关配置,存储采集来的数据存储 – 在 InfluxDB 中进行相关配置,存储采集来的数据

    图片

    3. 监控系统搭建方式

    windows环境搭建 JMeter + influxdb/prometheus + grafana 监控系统,展示效果如下:

    图片

    启动容器

    [root@localhost jkxt]# docker-compose up -d
    
    Creating jk_redis ... done
    Creating jk_cadvisor ... done
    Creating jk_prometheus ... done
    Creating jk_influxdb ... 
    Creating jk_redis ... 
    Creating jk_cadvisor ... 
    Creating jk_prometheus ... 
    
    [root@localhost jkxt]# docker ps
    CONTAINER ID   IMAGE                    COMMAND                  CREATED         STATUS         PORTS                                                                                                                             NAMES
    280c447c1e97   prom/prometheus:latest   "/bin/prometheus --c…"   2 minutes ago   Up 2 minutes   0.0.0.0:9090->9090/tcp, :::9090->9090/tcp                                                                                         jk_prometheus
    a00db4de47da   google/cadvisor:latest   "/usr/bin/cadvisor -…"   2 minutes ago   Up 2 minutes   8080/tcp, 0.0.0.0:8081->8081/tcp, :::8081->8081/tcp                                                                               jk_cadvisor
    5c04c5ebc022   redis:latest             "docker-entrypoint.s…"   2 minutes ago   Up 2 minutes   0.0.0.0:6380->6379/tcp, :::6380->6379/tcp                                                                                         jk_redis
    9edb14c81e3c   grafana/grafana:latest   "/run.sh"                2 minutes ago   Up 2 minutes   0.0.0.0:3000->3000/tcp, :::3000->3000/tcp                                                                                         jk_grafana
    c582e8e25dee   influxdb:1.8.10          "/entrypoint.sh infl…"   2 minutes ago   Up 2 minutes   0.0.0.0:8083->8083/tcp, :::8083->8083/tcp, 0.0.0.0:8086->8086/tcp, :::8086->8086/tcp, 0.0.0.0:8090->8090/tcp, :::8090->8090/tcp   jk_influxdb
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    配置好各个服务后,在浏览器中打开监控页面
    图片

    4. 监控系统为什么使用Docke-compose

    简化管理:虽然不像微服务架构动辄几十服务,监控系统涉及服务要是单独管理还是比较麻烦的,手动启停维护工作量较大。

    解决服务依赖性问题:监控系统服务存在依赖关系,需要相互配合才能实现监控系统的功能。

    可移植性:只需要编写一份docker-compse.yml,及提供相应服务的配置文件,可以快速移植到任何需要监控的服务器中

    总结

    以上内容是压测的一次概要描述,主要用于了解本次压测的背景,业务逻辑,压测指标,压测工具、压测流程 及 压测执行方式。


    资源分享

    下方这份完整的软件测试视频学习教程已经上传CSDN官方认证的二维码,朋友们如果需要可以自行免费领取 【保证100%免费】

    在这里插入图片描述

    在这里插入图片描述

  • 相关阅读:
    【剑指Offer】27.二叉树的镜像
    JavaScript入门--数组
    什么是脚本语言,解释脚本语言的特点和应用领域
    基于Vue+SpringBoot的海南旅游景点推荐系统 开源项目
    求合伙人 求一个会做大模型开发的老板。。
    C. Zero Path
    day25可变参数&综合练习
    ios 网站打包操作步骤介绍
    clickhouse union all之后数据量不一致
    Java---泛型
  • 原文地址:https://blog.csdn.net/wx17343624830/article/details/127687652