Skip to content

摸高压测实战教程

摸高压测实战

知识体系介绍

  • 性能压测工具(中级)
  • 性能监控(高级)
  • 性能分析(资深)
  • 性能调优(资深)

需求说明

对被测服务完成性能测试。

环境准备

  • 接口文档信息:https://ceshiren.com/t/topic/25854
  • 被测环境(网络不好可以直接让助教发zip包):https://github.com/princeqjzh/iJmeter

实战思路

  1. 单接口压测。
  2. 场景压测。
  3. 静默压测。
  4. 自动化压测。
  5. 性能结果分析。

JMeter 基本使用

工欲善其事,必先利其器。目前性能测试之中,最火最好用的工具一定是 JMeter。但是不管什么类型的性能测试工具,功能都是相通的,学工具一定要学会触类旁通,举一反三。而不是每个工具都花同等的时间再学一遍。

JMeter 的优点主要有:

  • 支持分布式测试。
  • 内置组件丰富。
  • 支持插件和扩展。
  • 多种输出格式。
  • 跨平台支持,Windows、Mac、Centos。
  • 开源免费。
  • 支持多种协议。
  • 支持多种数据格式。
  • 支持 UI 以及命令两种操作方式。

环境准备

  1. Java 环境准备: JMeter 的使用强依赖 Java 环境,所以需要提前安装好 Java 环境。

    • Java 环境验证: java --version
  2. 在 JMeter 官方网站下载相关的安装包:https://jmeter.apache.org/

  3. 压缩包解压安装,或直接进入 apache-jmeter-5.6.2/bin 目录启动 JMeter 工具。
  4. JMeter 环境验证:jmeter -v

JMeter 启动后通常会有以下相关提示:

# 不要使用GUI模式进行负载测试 GUI模式只是压测脚本的创建和调试
Dont use GUI mode for load testing !, only for Test creation and Test debugging.
# 如果想要进行负载测试 使用CLI模式 即非GUI模式 -- 静默压测会详细介绍
For load testing, use CLI Mode (was NON GUI):
   jmeter -n -t [jmx file] -l [results file] -e -o [Path to web report folder]
# 可以增加Java的堆来满足压测需求
& increase Java Heap to meet your test requirements:
# 修改JMeter文件的Java堆变量
   Modify current env variable HEAP="-Xms1g -Xmx1g -XX:MaxMetaspaceSize=256m" in the jmeter batch file

单接口压测-常见模块使用

首先进入第一个实战,第一个实战将通过一个单接口的压测实战学习 JMeter 的最常用组件。

测试计划

简介:

测试计划(Test Plan)描述了一系列 Jmeter 运行时将要执行的一系列步骤。完整的测试计划包含一个或者多个线程组,逻辑控制器,取样发生控制,监听器,定时器,断言和配置元件组成。

测试计划

参数说明

  1. 名称与注释。
  2. 用户定义的变量: 在测试计划上可以添加,相当于是全局变量。
  3. 独立运行每个线程组:
    • 用于控制测试计划中的多个线程组的执行顺序。
    • 不勾选时,默认各线程组并行、随机执行。
    • 如果勾选了独立运行每个线程组,可以保证按照顺序执行各线程组。
  4. 主线程结束后运行 tearDown 线程组: 当线程组停止运行时仍继续运行 tearDown 线程组,该选项结合线程组的执行配置使用,一般很少用到,了解即可。
  5. 函数测试模式(Functional Testing):如果选中了此选项,同时监听组件如“查看结果树”配置了保存到一个文件中,那么 jmeter 会将每次的请求结果保存到文件中。一般不建议勾选。
  6. 添加目录或 Jar 包到 ClassPath:当脚本需要调用外部的 java 文件或 jar 包时,可以把 jar 包路径添加到这里,然后在 beanshell 中直接 import 进来,并调用 jar 包中的方法。
线程组

什么是线程组:

  1. 线程组的主要作用为:性能测试的资源调度池。
  2. 控制性能测试的运行调度、参与人数(并发数)、执行策略。

线程组的重要组件

线程组名称 使用 应用场景
主线程组 测试计划的主要部分 模拟用户行为
SetUp 线程组 主线程组之前运行 设置测试环境(加载数据、添加配置)
TearDown 线程组 主线程组之后运行 清理环境、恢复设置、校验操作

线程组有哪些常见操作:

创建线程组

  • 第一部分:在请求取样器执行错误时需要执行的下一步动作
字段名称 字段含义
Continue 继续执行接下来的操作
Start Next Thread Loop 忽略错误,执行下一个循环
Stop Thread 退出该线程(不再进行此线程的任何操作)
Stop Test 等待当前执行的采样器结束后,结束整个测试
Stop Test Now 直接停止整个测试
  • 第二部分:线程属性
字段名称 字段含义
Number of Thread (users) 线程数,模拟的用户数量
Ramp-up Period(in seconds) 达到指定线程数所需要的时间。举例:线程数设置为 50,此处设置为 5,那么每秒启动的线程数 => 线程数 50/5 = 10
Same user on each iteration 每个循环使用相同的用户
Delay Thread creation until needed 当线程需要执行的时候,才会被创建。如果不选择这个选项,那么,在计划开始的时候,所有需要的线程就都被创建好了(JMeter 的设计机制)
Specify Thread lifetime 定义线程运行时间
Duration (seconds) 持续时间(秒), 在此选项填入 N,说明这个计划,从某个开始时间算起,执行 N 秒后结束。(会忽略 结束时间 的选项)
Startup delay (seconds) 启动延迟(秒),在此选项填入 N,手动点击开始执行计划,然后延迟 N 秒后,计划才真正开始执行。(会忽略 启动时间 的选项)
  • 关于 Ramp-Up Period 的几点说明:
    • 启动时间,准备时长
    • 从开始运行,到压力全部压上所需的时间
    • 模拟现实中的情形,并发启动不可能绝对同时
    • Ramp-Up Period
http 请求

简介:

JMeter 中的重要组件,用来控制 Http 请求(request),获取 Http 响应(response)

如何创建 http 请求:

  1. 打开 JMeter
  2. 新建压测脚本
  3. 添加 “Thread Group”
  4. 添加 “Http Request” Sampler 创建http 请求

http 用户登录请求配置:

  1. 定义请求名称:用户登录
  2. 配置 Host 、Port、Path = /api/v1/user/login
  3. 配置 Method = POST
  4. 添加接口请求参数 接口请求参数
头信息管理
  1. 在 Http Request 中添加 Http Header Manager, 管理该请求的 header 信息。
  2. 在 Http Header Manager 中配置如下参数。 Http Header Manager配置
JSON 断言

简介: 保证在性能测试过程中,接口的返回信息无异常无错误。

JSON 断言

查看结果树

简介:

运行并在 View Result Tree 中检查运行结果,查看每个接口(http 请求)运行的结果,除了查看运行的结果,还可以查看每个请求与响应的信息: 运行结果

压测实战

实战需求

  • 设定并发数
  • 设定运行时间
  • 解读压测报告
  • http vs https 协议速度

接口编写

创建浏览菜单接口请求

  • 添加 HttpRequest 请求
  • 配置请求名称:浏览菜单
  • 输入 hostname, port, path = /api/v1/menu/list
  • 设定 Method = GET

创建订单确认接口请求

  • 添加 HttpRequest 请求
  • 配置请求名称:订单确认
  • 输入 hostname, port, path = /api/v1/menu/confirm
  • 设定 Method = POST
// 请求体信息
{
  "order_list": [
    {
      "menu_nunber": "01",
      "number": 1
    },
    {
      "menu_nunber": "03",
      "number": 2
    },
    {
      "menu_nunber": "04",
      "number": 1
    },
    {
      "menu_nunber": "05",
      "number": 3
    }
  ]
}

创建用户注销接口请求

  • 添加 HttpRequest 请求
  • 配置请求名称:用户注销
  • 输入 hostname, port, path = /api/v1/user/logout
  • 设定 Method = DELETE
用户定义的变量

一旦涉及到多个接口的编写,我们会发现需要重复的写一些 Host、Port 等数据信息。这些数据信息,可以通过用户定义的变量进行复用。

使用方式:

  1. 创建并添加用户定义的变量。
  2. 使用 ${变量名} 的方式进行引用。

用户定义的变量

后置处理器- Json 提取器

应用场景:提取上一个接口的返回值给下一个接口

Json提取器

事务控制器

应用场景: 如果是统计一整个测试流程中的总计时间

  • 如果需要统计一组请求完成的总计时间,可以考虑使用事务控制器
  • 方法: 把需要统计的请求样本放入事务控制器中
  • 勾选: Generate Parent Sample
  • 注意: 事务的样本次数与最后一个接口的请求次数一致

事务控制器

数据参数化
  • 应用场景: 由于登录接口的互踢限制,并发的时候需要模拟不同的用户身份。
  • 组件应用: 配置元件->CSV 数据文件设置。
  1. 从 CSV 文件中导入多用户名 + 密码
  2. 解析 access token,获得用户的正确认证标识
  3. JMeter 中的参数传递

CSV数据参数化

常见问题
  • https 协议问题
  1. 网站使用机构可信证书:直接选择 https 协议即可
  2. 网站使用自建证书: 将网站证书导入 ssl manager 或 添加到系统的信任列表中 即可使用 https 协议 证书处理
  3. 添加到 ssl manager 中, 加入对应证书的 key 文件。位置: /application/cert_files/ 选择证书
  4. 运行时需要输入密码: 1234 输入密码
  • jmeter 中文显示问题的解决
    1. 解决乱码问题 -> 在/bin/jmeter.properties 配置文件中设置 sampleresult.default.encoding=utf-8
    2. 解决 Unicode 显示成可读中文的问题 -> 将 /unicode2utf8/unicode2utf8.js 内容复制粘贴到 BeanShell PostProcessor 中
聚合报告

聚合报告

  • Label:每个 JMeter 的 element 的 Name 值,例如 HTTP Request 的 Name;
  • 样本:发出请求数量;模拟 20 个用户,循环 100 次,所以显示了 2000;
  • 平均值:平均响应时间(单位:ms);默认是单个 Request 的平均响应时间,当使用了 Transaction Controller 时,也可以以 Transaction 为单位显示平均响应时间;
  • 中位数:50%的用户响应时间小于这个值;
  • 95%百分位:95%的用户响应时间小于这个值;
  • 99%百分位:99%的用户响应时间小于这个值;
  • 最小值:用户响应时间最小值;
  • 最大值:用户响应时间最大值;
  • 异常%:测试出现的错误请求数量百分比;请求的错误率 = 错误请求的数量/请求的总数;若出现错误就要看服务端的日志查找定位原因;
  • 吞吐量:Throughput 简称 TPS,吞吐量,默认情况下表示每秒处理的请求数,也就是指服务器处理能力,TPS 越高说明服务器处理能力越好;
  • KB/sec:每秒从服务器端接收到的数据量;
  • 异常%:确认是否允许错误的发生或者错误率允许在多大的范围内;
  • 吞吐量:吞吐量每秒请求的数大于并发数,则可以慢慢的往上面增加;若在压测的机器性能很好的情况下,出现吞吐量小于并发数,说明并发数不能再增加了,可以慢慢的往下减,找到最佳的并发数;
  • 接口返回信息的大小
  • 接口发出信息的大小

注意事项:

  1. 最大的 TPS:不断的增加并发数,加到 TPS 达到一定值开始出现下降,那么那个值就是最大的 TPS;
  2. 最大的并发数:最大的并发数和最大的 TPS 是不同的概率,一般不断增加并发数,达到一个值后,服务器出现请求超时,则可认为该值为最大的并发数;
  3. 持续的响应时间不一定是配置的时间,偶尔会超出去。
  4. 样本的数量不一定是配置的数量,因为有可能会被前面的请求占用对应的时间
  5. 压测的时候要时刻关注应用服务器数据库服务器等 CPU、内存、网络等使用情况;
  6. 压测过程出现性能瓶颈,若压测客户端任务管理器查看到的 CPU、网络和 CPU 都正常,未达到 90%以上,则可以说明服务器有问题,压测客户端没有问题;
  7. 影响性能考虑点包括:数据库、应用程序、中间件(php-fpm、nginx、redis…)、网络和操作系统等方面;

静默压测

价值:

脱离 UI 运行 JMeter 压测脚本

  • 命令格式: jmeter –n –t $jmx_file -l $jtl_file
  • jmx: JMeter 压测程序脚本文件,压测控制过程记录在 jmx 文件中
  • jtl 文件是 JMeter 压测请求响应数据的原始文件

Web 压测报告生成

  • 命令格式: jmeter -g /fullpath/result-file -e -o /fullpath/report/folder
jmeter -n -t [jmx file] -l [results file] -e -o [Path to web report folder]

-n: nongui
-t: testfile
-l: logfile
-e: 测试结束后的报告
-o :outputflolder 报告输出的文件地址

自定义参数示例

jmeter -n -t 压测脚本.jmx -l 不存在的文件名.jtl -e -o 为空的文件夹名 -J参数名1=参数值1  -J参数名2=参数值2

函数助手

  • 应用场景: 参数的定制化
  • 组件应用: 配置元件->CSV 数据文件设置。

自动化压测

价值:

使用自动化压测的原因是因为,如果手动逐步加压,则需要人肉改并发数,然后等待完成。整体的执行效率较低,所以,制定好策略,让程序自动加压,自动等待;完成后看压测监控记录,或者坐收报告。

实现思路:

  1. 使用 Shell 脚本进行逻辑控制,比如循环执行 JMeter 脚本
  2. 通过命令行导入并发数变量:
    • 变量命名规则:${__P(变量名称,默认值)},例如${__P(thread,10)}

程序流程图

# 压测脚本中设定的压测时间应为20秒
export jmx_filename="测试计划-单接口测试.jmx"

# 需要在系统变量中定义jmeter根目录的位置,如下,注意需要使用绝对路径
export jmeter_path=""

echo "自动化压测开始"

# 压测并发数列表
thread_number_array=(10 20 30)
for num in "${thread_number_array[@]}"
do
    echo "压测并发数 ${num}"
    # 定义jtl结果文件名与压测报告路径
    export jtl_filename="test_${num}.jtl"
    export web_report_path_name="web_${num}"

    rm -f ${jtl_filename}
    rm -rf ${web_report_path_name}

    # JMeter 静默压测 + 生成html压测报告
    ${jmeter_path}/bin/jmeter -n -t ${jmx_filename} -l ${jtl_filename}  -Jthread=${num} -e -o ${web_report_path_name}
    echo "结束压测并发数 ${num}"
done
echo "自动化压测全部结束"

结果分析

  1. 通过切换不同的并发数,收集不同的并发数结果。用以作为性能测试参考数据的范本。
  2. 设定测试期望结果: 并发数、峰值数。
  3. 定义错误率,定义可接受范围,错误率的设定通常和业务相关:
    • 比如微博、论坛类产品: <= 0.1% or <= 0.5%
    • 金融支付类产品:must = 0%
  4. 验证能够支撑多大并发数,峰值数。

寻找系统性能点示意图

以下是同一个服务,在不同的并发数的场景下,其吞吐量的变化:
压测实施计划

由上图可以看出来的是:

  1. 10 、50 、100 个并发时,每分钟的流量有明显变化。
  2. 当 200 个并发的时候,出现了明显的错误率,此时可能到达了系统的最大并发数
  3. 当 150 个并发的时候,错误率明显远低于 200 个,但是吞吐量和 200 个,以及 100 个没有太大的区别。代表可能在两个拐点的中间位置。
  4. 此时可以将并发数减少到 100 和 150 的中位数之间,比如选择 120,此时发现,120 个并发错误率为 0,并且其吞吐量也稍微高于 150 和 100。 所以可以得出的结论就是 120 个并发是目前此服务的最优并发数

性能结果分析技巧:通过对比并发数与流量还有错误率的关系,找到一个最合理的系统可支撑最大并发数。

  1. 第一轮压测:先把并发数往大增加,并且中间的数值差可以大一些,比如: 100,200,300,400,500。
  2. 第二轮压测: 需要从第一轮压测中找到错误率较高的一组数据(压出 error 的并发数)作为最大值;以及与其相近的那组数据作为最小值。比如最大并发数为 400,那么最小对应为 300。那么可以选择 300~400 之间的数据,比如:300, 310,350,380。
  3. 最终不停的缩小范围,即可找到最大并发数
  4. 注意:压测的错误率通常是有波动的,为了尽量保证稳定性,在每次压测之前重启 Server 或者压测时间设置长一点。