性能测试入门及JMeter、Gatling、ab、Siege、Wrk、Locust工具简介
性能测试
性能测试有两种类型,负载测试和压力测试:
- 负载测试(Load Testing):主要是测试软件系统是否达到需求文档设计的目标,如软件在一定时期内,最大支持多少并发用户数,软件请求出错率等。关注点是在满足响应正常的条件下,请求的极限值能有多高。
- 压力测试(Stress Testing):主要是测试硬件系统是否达到需求文档设计的性能目标,如在一定时期内,系统的CPU利用率,内存使用率,磁盘I/O吞吐率,网络吞吐量等。关注点是性能指标,给定一个较高的基准,系统的最好响应情况。
压力测试
压测时重点关注的指标:并发用户数、TPS(每秒事务数量)、RT(事务响应时间)、事务失败率、吞吐量、CPU(不要超过70%)和内存占用量。
注意事项:
- 测试机与被测试机要分开
- 不要对线上的服务器做压力测试
负载测试
负载测试
指标
性能测试时重点关注的指标数据:
- QPS,包括峰值QPS和单机QPS,
- TPS,Throughput,吞吐量:系统在单位时间内处理请求的数量
- 延迟,
- 吞吐率(Requests per second):总请求数 / 处理完成这些请求数所花费的时间
- 并发连接数(The number of concurrent users,Concurrency Level):一个用户可能同时会产生多个会话,也即连接数
- 用户平均请求等待时间(Time per request):处理完成所有请求数所花费的时间/ (总请求数 / 并发用户数)
- 服务器平均请求等待时间(Time per request: across all concurrent requests):处理完成所有请求数所花费的时间 / 总请求数
总结
一般情况是没有必要严格区别压力测试和负载测试,他们的目标都是为了评估系统的极限工作状态或者发现系统的性能瓶颈进一步做系统性能优化,下面列举的工具一般情况下对这两种测试场景都是支持的。
目标
- 发现系统的指标量级和性能瓶颈;
- 进一步为性能优化提供可视化的依据,故而最好需要压测工具自带生成报告的能力;
分类
性能测试,看要测试什么对象,如代码的执行性能,接口的耗时,单机的承载,DB的读写极限等,根据不同的待压测对象使用不同的工具:;
- 代码:JMH
- 接口:
- web:前端页面,知识盲区;
- DB:sysbench
应用类型,
CPU密集型应用
IO密集型应用
JMH
JMeter
另起一章,参考JMeter学习笔记
Gatling
官网:https://gatling.io/
Load test as code
使用Scala语言,从代码级别支持性能测试,能生成丰富多彩的报告,包含测试案例中收集的所有指标。同时提供脚本从命令行运行性能测试,支持录制(record)功能。
<dependency>
<groupId>io.gatling</groupId>
<artifactId>gatling-core</artifactId>
<version>3.3.1</version>
</dependency>
每一个Gatling测试都要继承 Simulation 类:
import io.gatling.core.Predef._
import io.gatling.http.Predef._
import scala.concurrent.duration._
class ApiGatlingSimulationTest extends Simulation {
// 定义protocol
val httpProtocol = http
.baseUrl("http://computer-database.gatling.io") // root URL for all relative URLs
.acceptHeader("text/html,application/xhtml+xml;q=0.9,*/*;q=0.8") // common headers
.doNotTrackHeader("1")
.acceptLanguageHeader("en-US,en;q=0.5")
.acceptEncodingHeader("gzip, deflate")
.userAgentHeader("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0")
// 一个repeat对应一次模拟测试,使用{}
val scn = scenario("InjectAndGet").repeat(1000, "n") {
exec(
http("AddPerson-API")
.post("http://localhost:8080/api")
.header("Content-Type", "application/json")
.body(StringBody("""{"firstName":"John${n}","lastName":"Smith${n}","birthDate":"1980-01-01", "address":{"country":"pl","city":"Warsaw","street":"Test${n}","postalCode":"02-200","houseNo":${n}}}"""))
.check(status.is(200))
)
// 还支持这种方式:.pause(629 milliseconds)
.pause(Duration.apply(5, TimeUnit.MILLISECONDS))
}.repeat(1000, "n") {
exec(
http("GetPerson-API")
.get("http://localhost:8080/api/${n}")
.check(status.is(200))
)
}
// 30个并发用户&测试10min
setUp(scn.inject(atOnceUsers(30))).maxDuration(FiniteDuration.apply(10, "minutes")
//.protocols(httpProtocol)
)
}
对于POST请求,除body.StringBody()
这种方式之外,还有formParam
:
.exec(
http("post-demo")
.post("/api")
.formParam("name", "Beautiful Computer") // Note the triple double quotes: used in Scala for protecting a whole chain of characters (no need for backslash)
.formParam("introduced", "2012-05-30")
)
配置maven插件:
<build>
<plugins>
<plugin>
<groupId>io.gatling</groupId>
<artifactId>gatling-maven-plugin</artifactId>
<version>${gatling-plugin.version}</version>
<configuration>
<!-- 测试脚本 -->
<simulationClass>com.anoyi.test.ApiGatlingSimulationTest</simulationClass>
<!-- 结果输出地址 -->
<resultsFolder>/Users/admin/code/gatling</resultsFolder>
</configuration>
</plugin>
</plugins>
</build>
执行命令:mvn gatling:execute
,生成的所有HTML报告都可以在performance-test/build/gatling-results
目录下找到
ab
Apache Benchmark,统计功能强大。默认使用GET方法测试,
Ubuntu安装:sudo apt-get install apache2-utils
Redhat安装:yum -y install httpd-tools
命令格式:ab -n 100 -c 10 'http://10.34.216.49:8000/test'
常用参数:
-c,concurrency,测试并发度,即连接数
-t,测试时间,此时默认-n默认为50000
-n,测试请求次数,一般-t或-n选一个
-p,postfile,读取json文本request,需要一并使用-T
-u ,putfile,发送PUT请求时需要上传的文件,需要一并使用-T
-T,Content-Type,指明请求数据格式
示例:
# 如果只用到一个Cookie,那么只需键入命令:
ab -n 100 -C key=value http://test.com/
# 如果需要多个Cookie,就直接设Header:
ab -n 100 -H "Cookie: Key1=Value1; Key2=Value2" http://test.com/
比较重要的返回信息:
信息 | 示例 | 解读 |
---|---|---|
Concurrency Level | 1000 | 并发数 |
Time per request(mean) | 465.338[ms] | 所有并发用户都请求一次的平均时间 |
Time request | 0.247[ms] | 单个用户请求一次的平均时间,计算全部次数的均值 |
Requests per second(mean) | 2148 | 平均每秒请求数,服务器的吞吐量 |
Percentage of the requests served within a certain time(ms) | 95% 846 | 95%的请求在846ms内返回,可看95线,99线 |
测试POST方法时,requestBody一般是json文本,需要放入txt格式文件中,且以''
括起来,使用-p -T
。
测试遇到:socket: Too many open files
时,需调整可打开文件数:ulimit -n 20480
问题:
- 无法直接在命令行测试不同URL,只能测试一个URL?
- 输出结果格式无法修改?
wrk
官网:https://github.com/wg/wrk
wrk 只能运行在类Unix 的系统上。
git clone源码make编译,make成功后同目录生成wrk文件,可复制到bin目录。
使用:
wrk <选项> <被测HTTP服务的URL>
-c, --connections,跟服务器建立并保持的TCP连接数量
-d, --duration,压测时间
-t,--threads,配置线程
-s, --script,指定Lua脚本路径
-H, --header,为每一个HTTP请求添加HTTP头
--latency,在压测结束后打印延迟统计信息
--timeout,超时时间
-v,--version打印正在使用的wrk的详细版本信息
# 其中数字参数,支持国际单位 (1k, 1M, 1G)
# 其中时间参数,支持时间单位 (2s, 2m, 2h)
示例:
wrk -t8 -c200 -d30s --latency "http://www.baidu.com"
Siege
官网:http://www.joedog.org/
一款HTTP/HTTPS负载测试和基准测试工具,支持基本身份验证、Cookie、HTTP、HTTPS和FTP协议,可配置模拟并发用户数。
安装:yum install siege -y
安装成功与否,查看版本:siege -V
help文档:
siege --help
-C, --config:查看siege当前的配置信息
-V, --version:版权说明信息
-c, --concurrent=NUM:并行启动(访问)用户数,默认是10
-t, --time=NUMm:压力测试时间,比如-t5表示持续时间是5分钟
-b, --benchmark:基准测试,请求之间没有延迟。
-g, --get get方式请求
-d, --delay=NUM 时间延迟,每个请求之间的延迟时间
-i, --internet 模拟用户,随机点击的URL
-r, --reps=NUM:每个连接发出的请求数量,与t有些类似,两者设置一个即可
-f, --file=FILE:对应一个文件,这个文件里每一行为一个URL链接,格式如:
-m, --mark="text" 在日志里标记的字符串标识
-H, --header="text" 在Header里增加的字符串标识
-A, --user-agent="text" 在user-agent里增加的字符串标识
-u, --url="URL",设置被测Web的URL
举例:10个并发,每个连接10个请求,间隔1秒请求压测。
siege -u www.baidu.com -d1 -r10 -c 10
HTTP/1.1 200 0.05 secs: 143913 bytes ==> GET /static/superman/js/lib/jquery-1-cc52697ab1.10.2.js
Transactions: 1017 hits // 总处理数量
Availability: 100.00 % // 成功请求百分百
Elapsed time: 10.06 secs //总耗时
Data transferred: 35.65 MB //总传输数据量
Response time: 0.03 secs // 响应时间
Transaction rate: 101.09 trans/sec // 每秒处理请求数
Throughput: 3.54 MB/sec // 吞吐量
Concurrency: 3.38 // 并发数
Successful transactions: 1017 //成功处理次数
Failed transactions: 0 //请求失败数
Longest transaction: 0.33 // 请求最长耗时
Shortest transaction: 0.00 //请求最短耗时
Locust
使用python语言写的分布式的压测工具,GitHub,有示例examples。
官网说明:
Define user behaviour with Python code, and swarm your system with millions of simultaneous users.
安装方式其一:pip install locustio
- gevent:在Python中实现协程的第三方库。协程又叫微线程Corouine。使用gevent可以获取极高的并发能力;
- flask:Python的一个web开发框架,和django相当;
- requests:支持http/https访问的库;
- msgpack:一种快速、紧凑的二进制序列化格式,使用与类似json的数据;
- pyzmq:MQ中间件,可以把Locust运行在多个进程或多个机器(分布式)
- geventhttpclient-wheels
- ConfigArgParse
- psutil
- Flask-BasicAuth
sysbench
模块化,跨平台以及多线程的DB性能测试工具