性能测试指标
响应时间
- 用户客户端呈现时间
- 请求/响应数据网络传输时间
- 应用服务器处理时间
- 数据库系统处理时间
并发用户数
吞吐量
性能测试:指单位时间内系统处理用户的请求数
业务角度:可以用请求数/秒,页面数/秒,人数/秒来衡量
网络角度:可以用字节/秒来衡量
TPS:每秒事务数
系统性能计数器
性能计数器(counter)是描述服务器或操作系统性能的一些数据指标。计数器在性能测试中发挥着“监控和分析”的关键作用,尤其是在分析系统的可扩展性、进行性能瓶颈的定位时,对计数器的取值的分析非常关键。但必须说明的是,单一的性能计数器只能体现系统性能的某一个方面,对性能测试结果的分析必须基于多个不同的计数器。
思考时间
用户每个请求之间的时间间隔
Jmeter使用步骤
- 创建测试计划
- 增加线程组
- 添加http请求 可以添加http请求默认值,url等不用每次都填
- 参数填入
- 如果操作中不通过,需要cookie,可以先写登录接口,在使用jmeter中的httpcookie管理器添加cookie
- 断言
- 增加查看结果树或报告
- 运行
fiddler
原理:
Fiddler通过改写HTTP代理,让数据从他那里过来监控并截取到数据
前后端问题定位
第一种情况:fiddler 没有设置过过滤器没有抓到请求信息,可能是前端页面元素没有绑定事件,也有可能是前端发生了JS 错误,这就是前端的bug 。
第二种情况:若抓取到的请求返回的结果错误,我们要确认一下,是否是前端传输的数据是错的,是的话就是前端的bug ,如果确定传值是正确的话,那就是后端的bug 。
第三种情况:若抓取到的请求返回值中间的http 的状态码是500的话,说明是后端服务器一般的内部错误,那这就是后端的bug 。
第四种情况:若抓取到的请求返回值中间的http 的状态码是404的话,说明可能后端服务器根本就没有对应地址的服务,当然还有可能是前端JS 提交请求的时候提交了错误的地址。
jmeter基本操作
执行顺序
1. 配置元件
2. 前置处理器
3. 定时器
4. 取样器
5. 后置处理器
6. 断言
7. 监听器
参数:表单 变量 值
消息体数据:json xml 表单是 a=1 b=2 c=3
文件上传:上传文件
配置元件
http请求默认值 为http请求设置默认值
http消息头管理器
httpcookies管理器
http cache管理器
监听器元件
- 查看结果树:分析查看具体某一个请求的详情(分析错误请求的原因)
- 请求头 请求体
- 响应头 响应体
- 聚合报告(汇总统计)
- 请求数,响应时间(平均的,min,max)单位ms
- 错误率
- 吞吐量
- 发送接收 带宽
-
表格查看结果
-
图形结果
前置处理器
后置处理器
定时器
- 思考时间-固定定时器
- 同步定时器-集合点
- 随机定时器
- 吞吐量定时器
断言(注意放置的作用域)
参数化流程
- 找出需要做参数化的数据
- 提供数据源
- 使用数据源数据把脚本里的常量变成变量
jmeter参数化方式
csv
- 新建txt文件,写入参数
- 在线程组中添加csv数据文件设置
文件名:引用在文件创建的用户名和密码参数值的txt文件;
变量名称:取给每列对应的数据取个变量名,通过${变量名}来获取参数值:
函数助手
- 函数助手进行参数化,前期和csv一样都要提前创建好含有参数值的txt文件
- 对http请求添加函数助手
- 在函数助手页进行设置,选择功能
- 将函数助手生成的函数字符串添加到变量的值里面,此处为form格式,如下图所示:
- 此处为json格式,如下图所示:
使用场景:账号密码
手机号已存在
使用参数化技术。函数助手random,设置135开头的手机号码 最小值及最大值 拷贝代码
- 函数式 随机数 time counter计数器
- 变量 添加用户自定义变量IP 在其他地方可以${IP}
- 编程式 引入外部jar java.class 使用beanshell编程
设置用户参数
1.在没设置用户参数之前,创建线程组
2.给用户添加变量:User parameters(用户参数):
3.用户变量放在线程组上面,给变量设置值:
3.在http请求中,将固定的ip地址和端口号改成刚刚添加的变量名:
用户自定义变量
1.给线程组添加自定义变量(User Defined Variables) 2.添加变量:
3.将http请求中的参数值替换为自定义变量:
4.运行
Jmeter接口关联
json path extractor
添加后置处理器变量为
添加debug(调式取样器) 查看是否拿到
在新增用户添加http请求头 添加参数名称和值
正则表达式提取器
- 一定要在查看结果树中的tester测一下,一般都是通过静态的边界值来定位动态的数据,将动态数据替换为(.*?)
- 在对应请求添加后置处理器-正则表达式提取器-名称为verify var verifyhash'(.*?)' 先存
- 查找所要替换的字段 替换为${verify} 或者手动去改 后用
参数:
-
apply to:控制正则表达式提取器的作用对象
-
- Main Sample:主请求
-
- Sub Sample:子请求 最后一个子请求作为主请求来展示
-
要检查的相应字段:指定数据的来源位置
-
- 主体:默认值,对应查看结果树
-
- 信息头:对应响应信息头
-
引用名称:即变量名称,由用户自定义
-
模板:可填写(位置变量,表示将第N对括号所对应的值存入变量)或常量字符串(以外的,即将字符串赋给变量)
-
匹配数字:正整数N 表示将第N次找到的数据赋值给变量
-
- 0(默认值) 表示随机抽取
-
- -1 表示将所有数据以类似数组的形式存入变量数组
提取多个值保存为一个字符串 引用名称:name_value
正则表达式:name="(.?)" value="(.?)"
模板:1 $$2$
输出:name_value=tomjerry
提取多个值分别保存
引用名称:name
正则表达式:name="(.?)" value="(.?)"
模板:$1
输出:name=tom
引用名称:value
正则表达式:name="(.?)" value="(.?)"
模板:$2
输出:value=jerry
遍历
①一次使用一个数据,使用N次可以用循环控制器或foreach控制器结合计数器使用
- 添加循环控制器
- 次数为${param_matchNr}(param是正则表达式的变量名称)
- 添加计数器
- 设置从1开始,递增为1,名称为index
- 添加V函数
- 在java请求中写入{V(param${index}.)}
②Allin 一次使用所有数据,使用一次,使用beanshell后置处理器
Jmeter集合点
让各个线程步调一致,对系统将进行加压,达到模拟真实并发访问的效果(synchronizing timer)
具体集合数不能大于线程数(没有超时一直等) 也不能小于线程数
Jmeter BeanShell
BeanShell是一种完全符合Java语法规范的脚本语言,是轻量级的Java脚本,所以BeanShell和Java是可以无缝衔接的。
特点:
1、完整的Java语法的动态执行,Java代码片段,以及松散类型的Java和其他脚本
2、透明地访问所有Java对象和API
// BeanShell
// 注意这里的打印是打印到Jmeter的控制台了
System.out.println("Hello, World");
log 打印日志
log.info("lxq") //输出到jmeter的日志中
log.error("lxq")
System.out.println("java控制台的打印") //输出到控制台
2.vars操作jmeter变量(只能在当前线程组使用)
- 用户定义变量
- 正则表达式,json提取器
- 定义变量
获取变量
log.info(vars.get("lxq"));
设置变量
vars.put("www","yyy");
3.props存取jmeter全局静态变量(可以跨线程组)
log.info(props.get("jmeter.save.saveservice.output_format"));
props.put("aaa","bbb")
4.prov获取前面取样器的值
log.info(prev.getResponseCode());
log.info(prev.getResponseDataAsString());
5.ctx 上下文
Jmeter中的BeanShell
1、定时器:BeanShell Timer
2、前置处理器:BeanShell PreProcessor
3、采样器:BeanShell Sampler
4、后置处理器:BeanShell PostProcessor
5、断言:BeanShell Assertion
6、监听器:BeanShell Listener
BeanShell把关联转化为参数化
问题
问题一:参数化数据量不足,比如:我要压测的某个接口依赖登录,先通过登录获取到tokenId(每个账号登录一次),然后把tokenId作为被压测接口的入参,如果账号不足,当我并发的线程数多于登录账号数量,前一次登录获取到tokenId值将失效,导致使用旧的tokenId的请求失败;
问题二:依赖请求的存在,导致被压测的接口性能不准确;
想法
为了解决上面的问题,我们可以不用关联,先单独操作依赖的请求,把需要获取的关联值存到文件中,被压测的请求就用文件参数化获取关联值,被关联的值可能是有有效时间的,我们可以找开发帮忙把有效时间设置长点,比如24h,这样就不用频繁重新获取关联值保存到文件中,毕竟我们是压测,不需要关注关联值的有效期限。
解决方法
删除已存在的参数化文件tokenId.txt
注意:后面要生成tokenId.txt这个文件,如果这个文件存在,我们先删除。
beanshell脚本
String filename ="C:/tokenId.txt";
File file = new File(filename);
if (file. exists())
{
file.delete();
}
生成参数化的文件tokenId.txt
因为只有100个账号,所以线程数设置为100,循环次数设置为1,即每个线程运行一次
a.登录接口需要的csv参数化文件userInfo.dat
注意,此参数化文件中有两列,第一列是卡号,第二列是登录账号
登录获取参数化文件中的登陆账号userAccount,而卡号cardNumber是被压测接口需要的参数
b.登录请求
正则提取tokenId
c.把关联获取到的值写入文件,因为被压测的接口需要用到tokenId和卡号cardNumber,所以需要把tokenId和卡号配对写在一行上,第一列是tokenId,第二列是卡号cardNumber
用包装流(BufferedReader)将字符输入流(FileReader)包装为缓冲字符输入流(BufferedReader)
生成的tokenId.txt文件,逗号分隔同一行的tokenId和卡号cardNumber两列数据
被压测接口脚本
这样,被压测接口就可以用上面生成的关联参数文件tokenId.txt了,下面变量名称和生成的tokenId.txt文件中变量顺序要一致
最终,我们就可以把脚本的重心完全放到被压测接口,而排除依赖接口的影响。
不同线程组之间的变量共享
思路:将某一线程组内的变量通过__setProperty函数设置成jmeter全局变量,在另一 个线程组中通过${__P(parameters)}函数调用即可。
说明:jmeter本身的内置函数中,__setProperty ({__setProperty(newtoken,{cookieKey},)})函数可以把某参数的值设置成jmeter本身的内置属性,而jmeter的内置属性是所有线程组都可以调用的,是全局变量。各个线程组调用时,只需使用调用jmeter属性的函数“${__P(parameters,)}”来调用相应的属性即可。
1.在http请求下添加正则表达式提取器 :
2.在请求下再添加Bean Shell PostProcessor(bean shell后置处理器)
Parametres:把需要操作的参数传递给Bean Shell PostProcessor
Script: string cookie=bsh.args[0]; 0是第一个值。
调用函数__setProperty,把Bean Shell PostProcessor中的参数cookie的值赋值给newcookie,并设置newcookie为jmeter内置属性。
${__setProperty(newcookie,${cookie},)};
Jmeter压测准备
1.运行场景 看聚合报告
- 响应时间
- 错误率
- 吞吐量
2.查看服务器资源 grafana看具体数据
发现问题 cpu使用率过高
- sys
- user 高 看哪个进程导致的
- idle
- io
3.看top资源查看具体哪个资源