作者:吴世超
什么是性能测试
性能测试是一种软件测试模式,重点关注运行零碎的零碎在特定负载下的性能。这与查找软件谬误或缺点无关。不同的性能测试类型依据基准和规范进行测量。性能测试为开发人员提供打消瓶颈所需的诊断信息。
性能测试的类型
次要的两种性能测试方法:负载测试和压力测试。然而,还有其余类型的测试方法可用于确定性能。一些例子如下:
- 负载测试:通常进行负载测试是为了理解零碎在特定预期负载下的行为表现。此负载能够是应用程序上的预期并发用户数,该应用程序在设定的持续时间内执行特定数量的事务。该测试将给出所有重要业务要害事务的响应工夫。测试期间还会监控数据库、应用服务器等,这将有助于辨认应用软件和装置软件的硬件中的瓶颈
- 压力测试:通常用于理解零碎内的容量下限。进行这种测试是为了确定零碎在极其负载方面的稳健性,并帮忙应用程序管理员确定如果以后负载远高于预期的最大值,零碎是否可能充沛运行。
- 浸泡测试:也称为耐久性测试,通常用于确定零碎是否可能接受继续的预期负载。在浸泡测试期间,会监控内存利用率以检测潜在的透露。同样重要但常常被忽视的是性能降落,即确保在长时间继续流动之后的吞吐量和响应工夫与测试开始时一样好或更好。它实质上波及在很长一段时间外向零碎施加大量负载。指标是发现零碎在继续应用下的行为形式。
- 尖峰测试:通过忽然减少或缩小大量用户产生的负载,并察看零碎的行为来实现的。指标是确定性能是否会受到影响,零碎会失败,还是可能解决负载的激烈变动。
- 断点测试:断点测试相似于压力测试。随着工夫的推移施加增量负载,同时监控零碎的预约故障条件。断点测试有时被称为容量测试,因为能够说它确定了零碎将依照其要求的标准或服务水平协定执行的最大容量。利用于固定环境的断点剖析后果可用于依据所需的硬件或应触发云环境中的横向扩大事件的条件来确定最佳扩大策略。
- 配置测试:不是从负载角度测试性能,而是创立测试以确定零碎组件的配置更改对系统性能和行为的影响。一个常见的例子是尝试不同的负载平衡办法。
- 隔离测试:隔离测试并不是性能测试所独有的,而是波及反复执行导致系统问题的测试。这样的测试通常能够隔离和确认故障域。
而咱们本次的测试实际采纳的是负载测试。
性能测试根本流程
测试环境是设置软件、硬件和网络以执行性能测试的中央。要应用测试环境进行性能测试,开发人员能够应用以下七个步骤:
-
确定测试环境:通过辨认可用的硬件、软件、网络配置和工具,测试团队能够设计测试并尽早辨认性能测试挑战。性能测试环境选项包含:
a. 生产零碎的子集,具备较少的低规格服务器
b. 具备雷同规格的较少服务器的生产零碎子集
c. 生产零碎正本
d. 理论生产零碎 - 确定性能指标:除了确定响应工夫、吞吐量和束缚等指标外,还要确定性能测试的胜利规范是什么,具体依据我的项目内团队规定。
- 打算和设计性能测试:思考到用户可变性、测试数据和指标度量的性能测试场景,能够创立一个或两个模型。
- 配置测试环境:筹备监控资源所需的测试环境机器和工具。
- 开发测试脚本
- 执行测试计划:运行性能测试,监控和捕捉生成的数据。
- 剖析、报告、从新测试:剖析数据并分享失去的性能论断。应用雷同的参数和不同的参数再次运行性能测试。
咱们在后续的实际中根本会遵循这个根本流程来开发。
性能测试工具
IT 团队能够应用各种性能测试工具,具体取决于其需要和偏好。性能测试工具的一些示例包含:
- JMeter:是一个 Apache 性能测试工具,能够对 Web 和应用程序服务进行负载测试。JMeter 插件在负载测试中提供了灵活性,并涵盖了图形、线程组、计时器、函数和逻辑控制器等畛域。JMeter 反对集成开发环境 (IDE),用于对浏览器或 Web 应用程序进行测试记录,以及用于负载测试基于 Java 的操作系统的命令行模式。
- LoadRunner:由 Micro Focus 开发,用于测试和测量应用程序在负载下的性能。LoadRunner 能够模仿成千上万的最终用户,并记录和剖析负载测试。作为模仿的一部分,该软件会在应用程序组件和最终用户操作之间生成音讯,相似于按键点击或鼠标挪动。LoadRunner 还包含面向云应用的版本。
- NeoLoad:由 Neotys 开发,为 Web 和挪动应用程序提供负载和压力测试,专门用于在公布前测试应用程序以实现 DevOps 和继续交付 IT 团队能够应用该程序来监控 Web、数据库和应用程序服务器。NeoLoad 能够模仿数百万用户,并在外部或通过云执行测试。
本次 PingCode 负载测试用到的测试工具就是 Jmeter。
性能测试指标
许多性能指标或要害性能指标能够帮忙 IT 团段评估以后零碎的性能情况。性能指标通常包含:
- 吞吐量:零碎在指定工夫内解决多少个信息单元。
- 响应工夫:从用户输出的申请到零碎开始响应该申请之间通过的工夫量。
- 带宽:每秒能够在工作负载之间挪动的数据量,通常是指通过网络。
- 每秒 CPU 中断次数:取的是平均值。指处理器每秒接管和解决的硬件中断数。
- 内存应用:计算机上过程可用的物理内存量。
- 磁盘应用:磁盘忙于执行读取或写入申请的工夫量
这些指标以及其余指标能够帮忙 IT 团队执行多种类型的性能测试。
本次负载测试实际中咱们次要关注的是:吞吐量、响应工夫、内存应用以及磁盘应用状况。
一次非系统性的性能测试实际
测试类型
负载测试:测试某个具体 API 在最大并发用户数,继续服务的 5Min,得出在基准环境下的 TPS 和 RT 值。
测试范畴
因为咱们的 API 很多,在短时间无奈全副测试结束,咱们采取优先测试「拜访度」高的 API。
最终决定将 API 服务近 6 个月拜访数量倒序排列取 10 个:
- 波及的子产品:Project , Testhub , Wiki , Insight , Goals , Flow 6 个子产品。
- 根底服务:Typhon 服务
测试目标
作为 Pingcode 我的项目首次性能测试,本轮测试的目标定义如下:
- 保障系统多用户状况下零碎的可靠性:通过施行不同的性能测试场景,评估并验证零碎在高负载下外围性能的可靠性。
- 提供一轮零碎性能测试状况,为下一轮生产环境的性能测试提供基线数据。
- 评估零碎部署资源的合理性:一直收集和剖析性能测试过程数据,对接下来的零碎部署所需的系统资源进行评估和倡议。
- 优化和解决零碎性能问题:在测试过程中,优化零碎各项参数和解决发现的零碎性能问题。
测试指标规范
- 依据运维提供的在线用户数,来计算生产环境的用户 TPS,通过基准环境的测试,来验证实在的 TPS 是否满足生产环境的 TPS 需要,以及咱们的运维架构和资源应用是否正当。
- 保障在 CPU 利用率小于 80%, 内存小于 80%,并且没有谬误的 Http 申请。
测试实际
测试工具
- 采纳 Jmeter + Grafana + Influxdb 的形式来实现性能测试。
- Jmeter GUI 图形界面工具:为了更不便开发和调试,应用图形界面编写所须要测试计划。
- Jmeter NO-GUI 模式:反对大型负载测试场景、进步脚本执行效率以及不便后续将脚本配置到 Jenkins 上实现继续集成,做成自动化测试。
环境搭建
- 装置 Java 的 Jdk,版本跟 Jmeter 版本绝对应。
- 装置 Jmeter 工具
Jmeter 中线程数取值根据
在理论的 Jmeter 测试实际中,咱们会通过线程数去模仿多用户的操作形式,然而这个线程数取多大的值才适合呢?
咱们能够通过上面两点估算出线程数:
- 首先要明确用户数、线程数、TPS 的关系
因为理论测试中响应工夫必定不会始终都是 100ms。所以通常状况下,下面的这个比例都不会变化无穷的,而是随着并发线程数的减少,会呈现趋势上的关系。
通过上图,咱们能够依据在线用户 10000,通过业内基准并发度 5%,计算出现实 TPS 为 500tps;或者依据产品间接给出的 500tps 作为现实 TPS。而这个现实的 TPS,会作为计算 Jmeter 线程数的基准。 - 通过 TPS 基准计算出压力机线程数
计算公式如下:
实际上,对于压力工具来说,只有不报错,咱们就关怀 TPS 和响应工夫就能够了,因为 TPS 反馈进去的是和服务器对应的解决能力,至多压力线程数是多少,并不需要关怀。
咱们会在前面的实际操作中,依据算进去的线程数去不停的调节从而失去 API 申请的理论 TPS 和 RT,和理论的 RT 状况与现实中 TPS 和 RT 做比照,来确定以后 API 性能状况。
Jmeter 我的项目目录构造
目前咱们测试过程中须要关注的是 bin
目录下的 templates
文件夹和 jmeter.properties
文件即可。
templates 文件夹
其中 templates.xml
文件是用来规定所要提供的测试计划模版列表,对应 Jmeter GUI 界面如下:
jmeter.properties 文件
其中 template.files 配置项是用来配置 Jmeter 所要读取的模版门路,但必须保障在 Jmeter 的装置根目录下,在前面的开发中为了不便存储会去批改此配置项。
我的项目筹备以及配置文件批改
为了不便多人合作开发,咱们应用代码版本管理工具 Github 来治理须要的模版和测试计划文件。为了不便上面应用,对立叫做 pc-perf
我的项目
克隆 Git 仓库
进入 Jmeter 的 bin 目录下
cd jmeter/bin
git clone [git 我的项目地址]
perf-test 目录
- common 文件夹:用来寄存本次测试计划模版以及模版配置文件 templates.xml。
- 子利用目录:与 common 同级目录是各子利用目录,如指标 Goals、我的项目 Project 等。该目录下用来寄存个子利用对应的 .jmx 测试计划文件。
批改 Jmeter 的配置文件 jmeter.properties
template.files = /bin/pc-perf/common/templates/templates.xml
JMeter 模版开发
通过 JMeter GUI 创立一个新的测试计划
增加 setUp 线程组元件用于获取登录信息
在 setUp 线层组下增加用户参数处理器
该用户参数处理器用来寄存一些用户级别的专用数据。例如:登录名、明码之类货色。
在 setUp 线程组下增加 BeanShell 预处理程序
该 BeanShell 预处理程序用来将专用属性全局化,全局的变量能够在多个线程组中调用。例如:申请协定、申请端口、IP、Host 以及 Influxdb 的链接等。
在 setUp 线程组下增加 http 申请取样器
补充 Http 申请取样器的内容
api 的信息,如申请头、IP、Port、Host、URL 申请体这些信息能够从 api 文档中获取。除此之外还能够通过浏览器自带的 copy fetch 的形式获取具体的接口信息。本次咱们采纳第二种形式获取 api 信息。
- 关上浏览器的开发者工具
因为 pingcode 我的项目登录后会重定向到我的项目首页,sigin 申请会一闪而逝,所以须要提前勾选好 Preserve log(保留日志)。 - 获取 signin 信息
咱们通过 Copy as fetch,能够失去如下代码:
fetch("http://at.pingcode.fun/**/signin",
{
"credentials":"include",
"headers":{
"accept":"application/json, text/plain, */*",
"accept-language":"zh-CN,zh;q=0.9",
"content-type":"application/json"
},
"referrer":"http://at.pingcode.fun/signin",
"referrerPolicy":"no-referrer-when-downgrade",
"body":"{\"signin_name\":\"**\",\"password\":\"**\",\"captcha_code\":\"\"}",
"method":"POST",
"mode":"cors"
});
从以上信息填充到 Http 申请取样器中
在 Http 申请取样器内增加 Http 信息头管理器元件
- 通过上一步能够在浏览器的开发者工具中 Copy request headers 获取残缺的申请头信息
- 通过元件自带的“从剪贴板增加”性能,一键配置申请头信息
在 Http 申请元件内增加 JSON 提取器
此提取器用来获取登录返回的信息。
从响应报文中提取数据有多种形式,详见:Jmeter 中响应报文的提取形式
在 Http 申请元件内增加调试后置处理程序
此元件能够在调试阶段查看 JSON 提取器获取的信息内容。
在 Http 申请元件内增加 JSR223 后置处理器
此元件用来格式化响应后果。比方获取相应用户、团队、token 等信息并放入到 Jmeter 的局部变量中。
- 应用 Javascript 语言来写脚本
- 提取用户、团队、token 信息
// 此处 loginResponse_1 是从 JSON 提取器的调试后果可失去
var loginResponseString = vars.get("loginResponse_1")
var loginResponse = JSON.parse(loginResponseString)
log.info("loginResponseString:"+ loginResponseString)
// 设置该线程组内的变量
vars.put("user", JSON.stringify(loginResponse.user))
vars.put("team", JSON.stringify(loginResponse.team))
vars.put("access_token", loginResponse.access_token)
在 Http 申请元件内增加 BeanShell 后置处理器
此元件用来将 token 等信息设置为全局变量供跨线程申请应用。
编写代码:
// 将用户、团队、token 信息申明成全局变量,用于前面线程组应用
${__setProperty(user, ${user})}
${__setProperty(team, ${team})}
${__setProperty(access_token, ${access_token})}
在 Http 申请元件内增加观察后果树监听器
此元件用来查看具体的 Http 申请详情。
运行测试计划
此时,根本一个残缺的申请就实现了,而后咱们启动该测试计划,查看运行后果。
还能够查看 JSON 提取器的取值状况:
JSON 提取器会将响应后果当作数组解决,因为 data.value
是单个对象,所以解决后的值为 loginResponse_1
优化参数治理
- 批改用户参数处理器
对立寄存用户名、明码、申请形式、申请 host 和申请端口,在其余元件或者脚本处理器应用:
局部变量调用形式:元件中应用:${key}
脚本中应用:vars.get(key)
- 批改 BeanShell 预处理程序
应用形式:
全局变量的调用形式:在元件中应用:${__P(key)}
在脚本中应用:props.get(key)
创立线程组 A
目前规定一个测试计划为 1 个子产品,一个线程组蕴含一个具体的子产品 API 申请。为了更好的统计信息,能够将 API 名字作为线程组名和申请名。
其中线程数咱们会利用下面所讲的计算公式计算出一个适合的线程数,例如线程数为 240。
那 Ramp-up 工夫应该取多少呢?咱们能够参考 ramp-up 定义以及取值来确定。比方:以 240 为线程数,ramp-up 就为 240。
在线程组 A 内增加 http 申请元件
在 Http 申请元件内增加申请头管理器
申请头中的 host 以及 token 都能够从全局变量中动静引入。
在 Http 申请元件内增加观察后果树元件
红框处设置后果写入的文件门路,目前是将后果写入到 jtl 格局的文件中,用于前期生成 html 测试报告。
在 Http 申请元件中增加后端监听器
此元件用于向 Influxdb 传输数据
在 Http 申请元件内增加聚合报告监听器
此元件可用于在 Jmeter 查看聚合后果。
此处跟传输到 influxdb,最终出现在 grafana 中数据差别不大。
Grafana 信息
application 为子利用名称,transaction 为 单个 API 申请。
将以后测试计划保留为模版
将模版保留到之前的 Git 仓库的 common 的 templates 目录下
通过 VsCode 批改 templates.xm 文件,将刚保留的测试计划配置到模版列表中:
name:模版名称,用于模版列表中展现
fileName: 要配置成模版的测试计划的门路
description:模版形容
parameters:模版参数,可通过模版 UI 页面对测试计划.jmx 文件动静传参。
批改 pingcode-perf-template.jmx 文件,接管模版传过来的参数 通过 [=key] 的模式接管模版的参数
开发子利用的 API 测试计划
通过批改导入的 JMeter 模版,来实现其余 API 测试。
点击模版工具栏,抉择要应用的模版
通过模版交互界面,输出对应的测试信息
编写 API 测试
因为目前规定同一个子利用的不同 api 在同一个测试计划下进行,所以确保测试计划的线程组执行形式为串行:
依据理论的 API 信息批改线程组 A 信息,顺次创立不同的线程组来实现子利用的其余 API 测试。
通过 Non-GUI 形式执行所有测试计划
命令行用法:
jmeter -n -t <testfile> -l <logfile>
示例:jmeter -n -t test.jmx -l test.jtl
解说:以命令行的形式运行 test.jmx 脚本并生成 test.jtl 的日志报告。-h 打印应用信息并退出
-n 非 GUI 模式 -> 在非 GUI 模式下运行 JMeter
-t 测试文件 < 参数 > -> 要运行的 jmeter 测试 (.jmx) 文件。-l 日志文件 < 参数 > -> 生成的日志文件
-H 设置要应用的 JMeter 代理服务器
-P 设置要应用的 JMeter 代理服务器端口
执行后果如下:
执行完所有测试计划后,通过 Grafana 查看 API 申请状况,依据 Influxdb 数据,统计所有 API 的理论 TPS 和 RT 数据。
到这里,咱们整个负载测试就实现了。接下来只须要将每个产品的 API 的理论 TPS 和 RT 状况统计下来,而后对这些数据进行剖析,咱们就能够失去这些 API 中哪些是须要优化的,从而达到咱们本次负载测试的目标。
材料
- 维基:< https://en.wikipedia.org/wiki…;
- Jmeter:< https://jmeter.apache.org/>
- LoadRunner:< https://en.wikipedia.org/wiki…;
- NeoLoad:https://www.tricentis.com/pro…