摸高压测实战教程
摸高压测实战
知识体系介绍
- 性能压测工具(中级)
- 性能监控(高级)
- 性能分析(资深)
- 性能调优(资深)
需求说明
对被测服务完成性能测试。
环境准备
- 接口文档信息:https://ceshiren.com/t/topic/25854
- 被测环境(网络不好可以直接让助教发zip包):https://github.com/princeqjzh/iJmeter
实战思路
- 单接口压测。
- 场景压测。
- 静默压测。
- 自动化压测。
- 性能结果分析。
JMeter 基本使用
工欲善其事,必先利其器。目前性能测试之中,最火最好用的工具一定是 JMeter。但是不管什么类型的性能测试工具,功能都是相通的,学工具一定要学会触类旁通,举一反三。而不是每个工具都花同等的时间再学一遍。
JMeter 的优点主要有:
- 支持分布式测试。
- 内置组件丰富。
- 支持插件和扩展。
- 多种输出格式。
- 跨平台支持,Windows、Mac、Centos。
- 开源免费。
- 支持多种协议。
- 支持多种数据格式。
- 支持 UI 以及命令两种操作方式。
环境准备
-
Java 环境准备: JMeter 的使用强依赖 Java 环境,所以需要提前安装好 Java 环境。
- Java 环境验证:
java --version
- Java 环境验证:
-
在 JMeter 官方网站下载相关的安装包:https://jmeter.apache.org/
- 压缩包解压安装,或直接进入
apache-jmeter-5.6.2/bin
目录启动 JMeter 工具。 - 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 运行时将要执行的一系列步骤。完整的测试计划包含一个或者多个线程组,逻辑控制器,取样发生控制,监听器,定时器,断言和配置元件组成。
参数说明
- 名称与注释。
- 用户定义的变量: 在测试计划上可以添加,相当于是全局变量。
- 独立运行每个线程组:
- 用于控制测试计划中的多个线程组的执行顺序。
- 不勾选时,默认各线程组并行、随机执行。
- 如果勾选了独立运行每个线程组,可以保证按照顺序执行各线程组。
- 主线程结束后运行 tearDown 线程组: 当线程组停止运行时仍继续运行 tearDown 线程组,该选项结合线程组的执行配置使用,一般很少用到,了解即可。
- 函数测试模式(Functional Testing):如果选中了此选项,同时监听组件如“查看结果树”配置了保存到一个文件中,那么 jmeter 会将每次的请求结果保存到文件中。一般不建议勾选。
- 添加目录或 Jar 包到 ClassPath:当脚本需要调用外部的 java 文件或 jar 包时,可以把 jar 包路径添加到这里,然后在 beanshell 中直接 import 进来,并调用 jar 包中的方法。
线程组
什么是线程组:
- 线程组的主要作用为:性能测试的资源调度池。
- 控制性能测试的运行调度、参与人数(并发数)、执行策略。
线程组的重要组件
线程组名称 | 使用 | 应用场景 |
---|---|---|
主线程组 | 测试计划的主要部分 | 模拟用户行为 |
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 的几点说明:
- 启动时间,准备时长
- 从开始运行,到压力全部压上所需的时间
- 模拟现实中的情形,并发启动不可能绝对同时
http 请求
简介:
JMeter 中的重要组件,用来控制 Http 请求(request),获取 Http 响应(response)
如何创建 http 请求:
- 打开 JMeter
- 新建压测脚本
- 添加 “Thread Group”
- 添加 “Http Request” Sampler
http 用户登录请求配置:
- 定义请求名称:用户登录
- 配置 Host 、Port、Path = /api/v1/user/login
- 配置 Method = POST
- 添加接口请求参数
头信息管理
- 在 Http Request 中添加 Http Header Manager, 管理该请求的 header 信息。
- 在 Http Header Manager 中配置如下参数。
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 等数据信息。这些数据信息,可以通过用户定义的变量进行复用。
使用方式:
- 创建并添加用户定义的变量。
- 使用
${变量名}
的方式进行引用。
后置处理器- Json 提取器
应用场景:提取上一个接口的返回值给下一个接口
事务控制器
应用场景: 如果是统计一整个测试流程中的总计时间
- 如果需要统计一组请求完成的总计时间,可以考虑使用事务控制器
- 方法: 把需要统计的请求样本放入事务控制器中
- 勾选:
Generate Parent Sample
- 注意: 事务的样本次数与最后一个接口的请求次数一致
数据参数化
- 应用场景: 由于登录接口的互踢限制,并发的时候需要模拟不同的用户身份。
- 组件应用: 配置元件->CSV 数据文件设置。
- 从 CSV 文件中导入多用户名 + 密码
- 解析 access token,获得用户的正确认证标识
- JMeter 中的参数传递
常见问题
- https 协议问题
- 网站使用机构可信证书:直接选择 https 协议即可
- 网站使用自建证书: 将网站证书导入 ssl manager 或 添加到系统的信任列表中 即可使用 https 协议
- 添加到 ssl manager 中, 加入对应证书的 key 文件。位置:
/application/cert_files/ - 运行时需要输入密码: 1234
- jmeter 中文显示问题的解决
- 解决乱码问题 -> 在
/bin/jmeter.properties 配置文件中设置 sampleresult.default.encoding=utf-8 - 解决 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:每秒从服务器端接收到的数据量;
- 异常%:确认是否允许错误的发生或者错误率允许在多大的范围内;
- 吞吐量:吞吐量每秒请求的数大于并发数,则可以慢慢的往上面增加;若在压测的机器性能很好的情况下,出现吞吐量小于并发数,说明并发数不能再增加了,可以慢慢的往下减,找到最佳的并发数;
- 接口返回信息的大小
- 接口发出信息的大小
注意事项:
- 最大的 TPS:不断的增加并发数,加到 TPS 达到一定值开始出现下降,那么那个值就是最大的 TPS;
- 最大的并发数:最大的并发数和最大的 TPS 是不同的概率,一般不断增加并发数,达到一个值后,服务器出现请求超时,则可认为该值为最大的并发数;
- 持续的响应时间不一定是配置的时间,偶尔会超出去。
- 样本的数量不一定是配置的数量,因为有可能会被前面的请求占用对应的时间
- 压测的时候要时刻关注应用服务器数据库服务器等 CPU、内存、网络等使用情况;
- 压测过程出现性能瓶颈,若压测客户端任务管理器查看到的 CPU、网络和 CPU 都正常,未达到 90%以上,则可以说明服务器有问题,压测客户端没有问题;
- 影响性能考虑点包括:数据库、应用程序、中间件(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 数据文件设置。
自动化压测
价值:
使用自动化压测的原因是因为,如果手动逐步加压,则需要人肉改并发数,然后等待完成。整体的执行效率较低,所以,制定好策略,让程序自动加压,自动等待;完成后看压测监控记录,或者坐收报告。
实现思路:
- 使用 Shell 脚本进行逻辑控制,比如循环执行 JMeter 脚本
- 通过命令行导入并发数变量:
- 变量命名规则:
${__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 "自动化压测全部结束"
结果分析
- 通过切换不同的并发数,收集不同的并发数结果。用以作为性能测试参考数据的范本。
- 设定测试期望结果: 并发数、峰值数。
- 定义错误率,定义可接受范围,错误率的设定通常和业务相关:
- 比如微博、论坛类产品: <= 0.1% or <= 0.5%
- 金融支付类产品:must = 0%
- 验证能够支撑多大并发数,峰值数。
以下是同一个服务,在不同的并发数的场景下,其吞吐量的变化:
由上图可以看出来的是:
- 10 、50 、100 个并发时,每分钟的流量有明显变化。
- 当 200 个并发的时候,出现了明显的错误率,此时可能到达了系统的最大并发数。
- 当 150 个并发的时候,错误率明显远低于 200 个,但是吞吐量和 200 个,以及 100 个没有太大的区别。代表可能在两个拐点的中间位置。
- 此时可以将并发数减少到 100 和 150 的中位数之间,比如选择 120,此时发现,120 个并发错误率为 0,并且其吞吐量也稍微高于 150 和 100。 所以可以得出的结论就是 120 个并发是目前此服务的最优并发数。
性能结果分析技巧:通过对比并发数与流量还有错误率的关系,找到一个最合理的系统可支撑最大并发数。
- 第一轮压测:先把并发数往大增加,并且中间的数值差可以大一些,比如: 100,200,300,400,500。
- 第二轮压测: 需要从第一轮压测中找到错误率较高的一组数据(压出 error 的并发数)作为最大值;以及与其相近的那组数据作为最小值。比如最大并发数为 400,那么最小对应为 300。那么可以选择 300~400 之间的数据,比如:300, 310,350,380。
- 最终不停的缩小范围,即可找到最大并发数。
- 注意:压测的错误率通常是有波动的,为了尽量保证稳定性,在每次压测之前重启 Server 或者压测时间设置长一点。