性能测试

272 阅读9分钟

性能测试

性能测试的目的

  1. 测试系统最大处理能力
    • 寻找系统最大的TPS,判断TPS和对应响应时间是否满足预期
  2. 测试系统支持最高并发
    • 寻找系统最高能支持多少并发,当系统出现宕机、进程崩溃、报错率持续上升、响应时间超过可忍受范围、程 序无响应等情况,即可认为系统达到了可支持的最高并发

性能测试分类

  1. 压力测试:通过模拟系统在高负荷、高并发和繁忙环境下的性能表现,以评估系统的响应能力和稳定性。 压力测试的核心逻辑:压力测试的逻辑

    收集数据 -> 数据分析 -> 创建场景-> 加压过程 → 收集指标 → 指标评定 ->定位瓶颈 → 优化验证 (例:数据库崩溃时需检查)  

    1. 连接池最大连接数是否过小  
    2. SQL是否存在慢查询  
    3. 是否触发了OOM机制
  2. 负载测试:通过模拟系统在不同负载和流量下的性能特征和响应时间,以评估系统的容量、可扩展性和吞吐量。

  3. 容量测试:通过模拟预期使用量、数据量和用户量不断增加的情况下,评估系统的容量、稳定性和资源利用率。

  4. 稳定性测试:通过长时间、持续的测试,以评估系统在长期运营和使用的情况下的稳定性。

性能测试指标

性能测试关注的指标:响应时间ms,TPS/QPS/RPS,错误率以及资源利用率,资源利用率一般在压测的过程中需要开发人员参与协助一起关注。

  • TPS:每秒事务数,衡量完整事务的处理能力,一个事务包含多步操作(需全部成功才算1次)
  • QPS:每秒查询数,衡量查询类请求的处理能力,侧重单次查询操作(如数据库查询、简单接口查询)
  • RPS:每秒请求数,衡量所有请求的处理能力,最宽泛的指标(无论请求类型、是否包含多步操作)

三者差异

  1. TPS强调业务

    • 电商下单业务,包含3个操作:
    • 检验库存(调用库存接口)->创建订单(调用订单接口)->扣减余额(调用支付接口)。只有这3步全部执行成功,才算1次下单事务,统计为1TPS。
    • 常用于评估系统的业务处理能力(如每秒能处理多少笔订、多少笔转账)
    • TPS=1000ms/响应时间(ms)*压力机线程数
  2. QPS强调数据读取

    QPS的核心是每次查询操作,只要请求成功就统计为1次QPS。QPS更贴近技术视角,常用于评估查询密集型系统的处理能力(如搜索引擎、商品列表页、数据库只读服务)。

    QPS不一定等于接口调用次数,若一个接口内部包含3次数据库查询,接口调用1次算1QPS,但数据库层面会产生3次查询操作(此时数据库的QPS是3)。

  3. RPS聚集所有请求

    RPS统计的是每秒发送的所有请求数据,无论请求类型、是否包含多步操作、是否成功,只要发送了请求,就会被统计。

    • 每秒改善50次下单请求(每个下单包含3步接口调用)--接口层面的RPS就是50*3=150,业务层面的RPS就是50.
    • RPS是通用指标,常用于初步评估系统的请求承载量(如压测工具JMeter)

    image.png 计算:数量/总时间(单位时间内完成的数量)

事务通常是由多个请求或者查询来完成,查询商品的事务(查询商品分类请求,查询商品数量请求,查询价格请求)可以去认定为当前服务器1T/S,RPS:3R/S。

性能测试需要定个目标1000r/s 响应时间1000ms

  1. 吞吐量 网络中上行和下行的流量总和,吞吐量代表网络的流量,TPS越高,吞吐量越高

性能测试流程

性能测试场景分类

  1. 基准测试场景

    单业务的容量测试

    作用:在无压力场景下,单业务响应时间标准,以及获取单业务最大容量,为后期混合测试场景提供参考。

  2. 容量场景

    也即根据生产实际情况,按比例混合待测试的所有业务。

  3. 稳定性场景

    针对混合比例业务场景,选取一个容量,进行长时间的压测,观察系统的响应。

  4. 异常场景

    根据系统实际的架构,模拟异常情况下系统的处理能力,以及系统恢复后,TPS、响应时间是否能够恢复。

压测模型

  1. 普通线程组:给定线程数,持续时间。
  2. 阶梯式加压:使用Ultimate Thread Group
  3. 多业务按比例加压 假设 业务1:业务2=1:2
业务名称响应时间
业务1200ms
业务2500ms

现在设置阶梯式加压

线程数配置=TPS/(1000ms/预期响应时间) image.png

在jmeter中多线程配置,在测试计算中添加两个线程组:每个线程组单独配置线程数和取样器。

二八模型

80%的请求都集中在20%的时间内

网站的注册用户1000w,日活跃用户大概是100w左右,那么最极端情况下,这100w人都会来签到,那么每天大概有100w次签到请求,80%的请求数就是100w*0.8=80w。 其次确定系统的20%时间,大多数系统是24小时对外提供服务的,但是大多数系统在0点到6点之间访问量很少,可以忽略不计。减去6个小时,还剩下18个小时,那20%的时间=18小时*3600秒*0.2=12960秒。 最终计算结果为80w请求/12960秒=61左右,即TPS满足61即可。 再乘以冗余系统,一般在2-5之间。取3,61*3=183。

二八定律的算法为:80%的请求/20%的时间*冗余系数

单个接口加压

查找TPS没有明显增长的时间,对应时间的线程数,随着继续加压,线程数增多,TPS没有增多,响应时间增加,继续加压,响应时间会猛增,TPS到极限了,大致计算出TPS的极限

混合测试比例

根据多个接口请求的比例,进行分配TPS。不同阶段有不同的总TPS。

image.png

三个接口选择三个终极线程组 image.png

每个终极线程组的线程数量,启动时间,运行时间

image.png

Jmeter

线程组:就是虚拟用户

image.png

  • 线程数:虚拟用户数量
  • Ramp-Up时间:共计从0开始到达到最大线程数的时间,如果设置为0,表示多个线程同时并发
  • 线程数是10,并且ramp up时间是10s,那么jmeter将用10秒加载10个线程,也就是平均1秒加载一个虚拟用户
  • 循环次数:线程组每个线程的重复次数。设置成永远,则会一直重复运行。
  • 持续时间:设置持续时间

取样器

自定义变量${var}

image.png

image.png

获取登录的token:请求登录接口后,从查看结果树,获取 json格式的响应体,得到token

http请求的取样器结果

  • Connect Time:jmeter和被测试系统建立TCP连接的时间,包括3次握手时间,如果连接复用,值为0
  • lantency:从发出请求到接收完第一个响应的时间
  • loadtime:从发出请求前到接收完所有响应的时间,如果是长消息,往往时长大于等于lantency,因为有多个响应

TCP取样器

image.png

断言

JSON断言 image.png

响应断言

image.png

响应断言模式匹配规则

  • 包括(Contains):如果响应中包含了指定的字符串,判断为成功,支持正则表达式
  • 匹配(Matches):如果响应完全匹配指定的字符串,判断为成功,支持正则表达式
  • 相等(Equals):如果响应完全匹配指定的字符串,判断为成功,不支持正则表达式
  • 子字符串(Substring):如果响应中包含了指定的字符串,判断为成功,不支持正则表达式

配置元件

HTTP信息头管理器:Content-Type=application/json;charset=UTF-8

用户自定义变量 image.png

CSV数据文件设置

线程组-->添加-->CSV数据文件设置,读取csv文件里每行数据 image.png

Random CSV Data Set Config

插件,随机读取csv文件中的某一行

计数器

image.png

常见函数

_Randoom():生成随机数字 image.png

_RandomString:生成随机字符串 image.png

CsvRead:读取csv文件 image.png

  • 时间戳: ${_time(,)}
  • 生成唯一UUID: ${_UUID}
  • 生成当前日期:${_timeShift(yyyy-MM-dd,,P2D,,)}

监听器

聚合报告

吞吐量——默认情况下表示每秒完成的请求数(Request per Second),对于接口测试来说,Jmeter里的吞吐量=TPS

image.png

三个监听器插件

image.png

三个监听器

image.png

Custom Thread Groups插件

包含Stepping Thread Group(阶梯线程组), **Ultimate Thread Group(终极线程组)**等常用元件

  • start thread count:加载多少线程
  • initial delay,sec:线程延迟多长时间开始运行
  • startup time,sec:线程加载多长时间
  • hold load for,sec:线程持续运行多长时间
  • shutdown time:在多长时间内停止所有线程

定时器

  1. 定时器是在每个sampler(采样器)之前执行的,而不是之后,类似于sleep()函数
  2. 定时器是有作用域的;当执行一个sampler之前时,所有当前作用域内的定时器都会被执行。且 所有的sampler执行前都会执行定时器
  3. 如果希望定时器仅应用于其中一个sampler,则把该定时器作为子节点加入

固定定时器

设置一个固定的延迟时间,单位ms

image.png

同步定时器

同步定时器(synchronizing timer):在该定时器处,使线程等待,一直到指定的线程个数达到 后,再一起释放。可以在瞬间制造出很大的压力。

image.png

统一随机定时器

比如设置固定延迟时间为2000毫秒,最大随机时间为500毫秒,那么总的延迟时间范围是2000毫秒~2500毫秒之间的值 image.png

吞吐量定时器

以指定数字的吞吐量(即指定TPS),要求指定每分钟的执行数。吞吐量计算的范围指定为当前线程组中的所有活动线程

响应时间258原则

基于用户角度实现:二秒内优秀、五秒一般、八秒问题

Response Times Distribution

响应时间分布:柱状图,x轴:响应时间,y轴:请求数量;查看不同响应时间的请求数量

后置处理器

JSON提取器

匹配数字:0代表随机, n代表具体的数字, -1代表所有

image.png

正则表达式

把目标数据用.+?代替

模板: 11表示取匹配到的第一组数据, 22为第二组

匹配数字:当某组数据中包含多少个参数时,0代表随机, 1代表该组的第一个参数,2表示第二 个。。。 -1代表获取全部的参数,这个时候,引用名称就变成了参数数组,可以通过param_n来 获取指定的参数,当有多组数据时,第一组为param_1_g1,第二组为param_1_g2

image.png

常用正则表达式

image.png

逻辑控制器

循环控制器:可以设置该控制器内的取样器执行的次数,循环次数与线程的循环次数各自独立

if控制器:根据判断条件决定是否执行该控制器内的请求,如果是字符串比较条件,参数和字符串 都需要加引号

${__jexl3(条件表达式)}

如:${_jexl3(${num} > 10)}${_jexl3(“${num}” == “10”)}

image.png

仅一次控制器:该控制器内的请求只执行一次,无论线程循环多少次

while循环控制器

image.png

foreach控制器,可以遍历某个参数数组,循环获取数组中的参数

image.png

吞吐量控制器

一个业务有多个请求,控制业务内不同请求的数据占比 image.png

事务控制器

将多个接口封装成一个事务 image.png

上传与下载

上传

上传不同类型的文件

  • 'txt': 'text/plain',        # 文本文件
  • 'pdf': 'application/pdf',   # PDF文档
  • 'png': 'image/png',         # PNG图片
  • 'jpg': 'image/jpeg',        # JPEG图片
  • 'jpeg': 'image/jpeg',       # JPEG图片
  • 'gif': 'image/gif'          # GIF图片
  • 'jar': 'application/java-archive'
  • MIME类型: application/octet-stream

image.png

下载

普通get请求

webservice接口

post请求,添加header:Content-type:text/xml

参考接口:ws.webxml.com.cn/WebServices…

xml格式

HTTP消息头管理器:Content-type=text/xml; charset=utf-8

image.png

JMeter连接数据库

数据库连接配置

线程组->添加->配置元件->JDBC Connection Configuration image.png

  • Connection Validation by Pool:验证连接池是否可响应
  • Test While Idle:当连接空闲时是否断开
  • Soft Min Evictable Idle Time(ms):连接在池中处于空闲状态的最短时间
  • Validation Query:一个简单的查询,用于确定数据库是否仍在响应;默认为 jdbc 驱动程序的 isValid() 方法, 
  • Database Connection configuration ---数据库连接配置
  • Database URL:数据库连接 URL  如jdbc:mysql://{ip}:{port}/{dbname}
  • JDBC Driver class:数据库驱动(选择对应的数据库驱动)
  • Username:数据库登录用户名
  • Password:数据库登录密码
  • Connection Properties:建立连接时要设置的连接属性
  • jdbc:mysql://localhost:3306/heihe_mall?useSSL=false&serverTimezone=Asia/Shanghai

JDBC请求

在JDBC Request中,需要配置以下信息:

image.png

select参数化:sql语句中的数值用?代替

  • Parameter values:代替sql语句中的问号的数据
  • Parameter types:数据库字段数据类型,如VARCHAR,INTEGER
  • Variable Names:变量名称,跟SQL语句中查询字段数量保持一致

JDBC与ForEach

image.png

在后续的HTTP请求或其他取样器中,可以通过${变量名_索引}的方式引用查询结果。例如,第一个name的值可以通过${name_1}引用

beanshell

内置变量

beanshell脚本中不用定义,可以直接使用的变量,常用的内置变量和方法如下

  • log :写日志到控制台和jmeter.log ,如log.info(“xxxxx”);
  • vars:操作jmeter变量
  • vars.get(“skuId”);从jmeter中获取${skuId}变量的值
  • vars.put(“name”,”test”);将”test”保存到${name}变量中
  • prev:获取前面sampler返回的信息
    • getResponseDataAsString():获取响应信息
    • getResponseCode():获取响应code
当20个用户访问产品列表时,QPS达到30时的平均响应时间是多少

三个参数

操作步骤:

  • 线程数:虚拟用户数,一个虚拟用户占用一个线程或进程
  • 准备时长(单位s):设置虚拟用户数需要多长时间全部启动,如果线程数是20,准备时长是10,那么需要10秒钟启动20个线程。也就是每秒启动2个线程。
  • 循环次数:每个线程发送请求的次数。如果线程数为20,循环次数为5,那么每个线程发送5次请求,总请求数为100

image.png

image.png

image.png

Jmeter命令行

压力机配置jdk

  1. 上传jdk-8u221-linux-x64.tar.gz 到 Linux 的/usr/local 目录下
  2. 解压:tar xvf jdk-8u221-linux-x64.tar.gz
  3. 修改配置文件:vi /etc/profile
  4. 光标移动到最后一行 ,添加以下配置
export JAVA_HOME=/usr/local/jdk1.8.0_221
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

5. 退出 vi,执行命令 source /etc/profile,让配置生效 6. 执行 java -version 命令,如果能看到版本信息,配置成功

  1. jmeter脚本上传到虚拟机
  2. 进到Jmeter 根目录下需要添加执行权限 chmod -R +x ./*
  3. 将apache jmeter压缩包复制到虚拟机
  4. 解压缩:unzip jmeter.zip
  5. 进入bin目录下,将jmeter.sh加上执行权限
  6. 在bin目录下运行./jmeter -n -t xxx.jmx -l result.jtl

单机器测试步骤

jmeter -n -t d:\xxx.jmx -l result.jtl -j run.log -R ip1:port1,ip2:port2

  • -n:不要图形化
  • -t:运行指定目录的jmx文件
  • -l:jmx运行的数据保存到result.jtl
  • -j:日志文件保存到run.log
  • -R ip1:port1,ip2:port2:使用远程负载机ip1和ip2,同时执行jmx脚本

如果使用jmeter执行24小时稳定性测试,在长时间无操作的情况下,一般终端工具会自动断开ssh连接,导致进程中断,可以配合使用nohup命令进行后台执行。nohup jmeter -n -t

  • 使用jtl文件生成html报告,保存在当前目录html/test下:jmeter -g result.jtl -e -o html\test (jmeter.properties中,jtl文件也是配置为csv的情况下)

jmeter.properties中jmeter.save.saveservice.output_format=csv注释去掉

  • 实现参数的传递
    • ${__P(thread.num)}变量名thread.num
    • ${__P(rampUp.time,1)}变量名rampUp.time,默认值1、
    • ${__P(run.time,300)}变量名run.time,默认值300
    • ${_property(thread.num,t_num,1)}变量名称thread.num赋值给变量t_num,默认值为1

image.png 通过-D 来实现参数的传递

jmeter -n -t p.jmx -l result.jtl -D thread.num=5 -D rampUp.time=10 -D run.time=30 -e -o html/test命令执行测试,表示使用5并发,在10s尽快上用户,共执行30秒的测试场景

JMeter参数优化

  1. 控制台取样间隔的设置:jmeter.properties文件中summariser.interval=10,默认为30s,最低可修改为6s
  2. 修改-e -o生成的测试报告的数据展示间隔,进入bin目录下的reportgenerator.properties文件,修改jmeter.reportgenerator.overall_granularity=1000,单位毫秒

JMeter分布式部署

win电脑要ping通虚拟机

虚机机设置固定ip

  1. 进入vim /etc/sysconfig/network-scripts/ifcfg-ens33
  2. 修改ifcfg-ens33为静态ip
TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=static
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6_ADDR_GEN_MODE=stable-privacy
NAME=ens33
UUID=b8fe563d-0238-4120-a197-5eb48cc13bb3
DEVICE=ens33
ONBOOT=yes
IPADDR=192.168.88.131
NETMASK=255.255.255.0
GATEWAY=192.168.88.1
DNS1=8.8.8.8
  1. 重启网络服务systemctl restart network

JMeter数据监控

  1. Influxdb结果收集

    InfluxDB 是一款专为处理时间序列数据设计的开源数据库,广泛应用于物联网(IoT)、监控、实时分析等场景。以下是其核心特点和说明:

核心特性

  • 高性能:支持每秒百万级数据点写入,适合高频数据采集。
  • 时间戳驱动:所有数据自动关联时间戳,内置时间窗口(如分钟、小时)查询能力。
  • 标签与字段:通过标签(Tags)做索引(如设备 ID、地理位置),字段(Fields)存储数值型数据(如温度、压力),查询效率极高。
  • 内置函数:提供聚合、统计、插值等时间序列专用函数(如mean()、max()、derivative())。
  • 数据保留策略:可自定义数据存储时长(如 30 天、1 年),自动清理过期数据。
centos安装Influxdb
  1. 下载:wget https://dl.influxdata.com/influxdb/releases/influxdb-1.7.1.x86_64.rpm
  2. 安装:yum install influxdb-1.7.1.x86_64.rpm
  3. 启动influxdb.service服务:systemctl start influxdb.service
  4. 查看服务使用端口:使用两个端口8088和8086,8086端口是Grafana从数据库获取数据的端口、也是jmeter写数据的端口
netstat -lntp |grep `ps -ef |grep influxdb |grep -v grep |awk '{print $2}'`