我们有些时候想快速验证我们的解决方案是不是存在性能问题, 或者在并发情况下是否有意想不到的问题. 安装 LoadRunner 这样工具, 录制脚本很麻烦, 用起来就像在用大炮打蚊子.
wrk 是一个比较先进的 HTTP 压力测试工具。wrk负载测试时可以运行在一个或者多核CPU,wrk结合了可伸缩的事件通知系统epoll和kqueue等多线程设计思想。目前wrk可以安装在Linux系统和Mac系统。只有一个命令行, 就能做很多基本的 http 性能测试.
下载源代码
https://github.com/wg/wrk
使用参考
https://www.cnblogs.com/savorboard/p/wrk.html
https://zjumty.iteye.com/blog/2221040 (写的比较好)wrk 提供的几个 lua 的 hook 函数:
安装参考
[程序员赵鑫] http://www.cnblogs.com/xinzhao/p/6233009.html
例子:表单的提交
wrk.method = "POST"
wrk.body = "" -- 直接写死,如果不需要请求数据的差异化
wrk.headers["Content-Type"] = "application/x-www-form-urlencoded"
-- 如果要实现每次都不一样的表单内容
local queries = {
"language=php",
"language=java",
"language=lua"
}
local i = 0
request = function()
local body = wrk.format(nil, nil, nil, queries[i % #queries + 1])
i = i + 1
return body
end
300线程跑60秒:Requests per second=2301.68
500线程跑60秒:Requests per second=2279.27
可见线程数加到500,还不如300的了,所以有时候线程数不是加的越高越好,更根据服务器的配置,CPU,IO,带宽等的消耗设置合理的线程数
细心的读者可能看出,我虽然设置了-t参数为60s,但实际只运行了20多秒,因为ab跑满50000个request就自己停了,想跑够60s可以使用-n参数
如果post请求的body不为空则指定lua文件进行读取,示例如下:
./wrk -t 5 -c 300 -d 60 --script=post.lua --latency https://api.midukanshu.com/logstash/userbehavior/create
post.lua文件内容
wrk.method = "POST"
wrk.body = ""
wrk.headers["Content-Type"] = "application/x-www-form-urlencoded"
Keith Mo #5 · 2018年08月27日
http_load 06年的过时东西了就别提了吧……
ab不推荐,content-length长度变了也当成错误,而且单线程是个瓶颈,用nginx-status页面做测试,客户端找台8核以上的服务器,跑一下就知道和wrk差距有多大了。
小工具推荐 wrk2,https://github.com/giltene/wrk2,是 wrk 的分支。推荐看看作者 Gil Tene 在 readme 里写的关于如何正确测量响应时间,推荐搜一下作者讲 coordinated omission(CO) 的 2 个youtube视频。
wrk 也可用,性能也更好些。建议跟 wrk2 对照,毕竟CO是个大坑,全世界绝大部分压测工具都掉坑里。
locust (基于python开源)不推荐,一是作者看上去不知道自己在做什么,二是框架性能和报告功能都极差,有这功夫填坑不如找个更正经的框架二次开发。(locust可以和HttpRunner结合实现监控作用。)
ngrinder 不推荐,往往是只做过demo的人才吹它的开箱即用。github上2年多没更新了,跟死了差不多。
taurus + jmeter(基于java开源)组合现在很流行,算是可用,但小心CO问题。它的命令行报告生成的网页里,首页的响应时间百分位数统计不一定可靠,注意点开看菜单里的各种overtime图表。坑踩得少的人很容易用它骗自己接口的响应时间没问题。现在项目里已经基本抛弃它了。
愿意封装和写代码的话推荐 Gatling。动手封装前最好搜一下一篇貌似叫 close workload model vs open workload model 之类的论文,06年的。Gatling 要用 open workload model,也就是指定 RPS 然后它每秒新建这么多连接,才能避免 CO 问题。
参考文档 https://testerhome.com/topics/15772?locale=zh-CN
压测线程不宜过多
一般线程数不宜过多,核数的2到4倍足够了,多了反而因为线程切换过多造成效率降低,因为wrk不是使用每个连接一个线程的模型, 而是通过异步网络io提升并发量,所以网络通信不会阻塞线程执行,这也是wrk可以用很少的线程模拟大量网路连接的原因,而现在很多性能工具并没有采用这种方式, 而是采用提高线程数来实现高并发,所以并发量一旦设的很高, 测试机自身压力就很大,测试效果反而下降。
压测结果几个重要指标:
一般我们最关心的几个结果指标
1、Latency: 可以理解为响应时间分布。
2、Requests/Sec: 每秒的处理请求数,可以理解为tps。
3、连接超时数目timeout。
高级应用(动态化请求参数):
在lua脚本里你可以修改 method, header, body, 可以对 response 做一下自定义的分析。
注意: 一般修改method, header, body不会影响测试端性能, 但是操作 request, response 就要格外谨慎了。
get动态参数
post动态参数
brew install wrk
1.git clone下载源代码
2. cd wrk,make
3.make之后,会在项目路径下生成可执行文件wrk,随后就可以用其进行HTTP压测了。
4. cp wrk /usr/local/bin 可以把这个可执行文件拷贝到某个已在path中的路径,比如/usr/local/bin,这样就可以在任何路径直接使用wrk了。
配置修改LuaJIT和OpenSSL(非必须步骤)
默认情况下wrk会使用自带的LuaJIT和OpenSSL,如果你想使用系统已安装的版本,可以使用WITH_LUAJIT和WITH_OPENSSL这两个选项来指定它们的路径。比如:
make WITH_LUAJIT=/usr WITH_OPENSSL=/usr
命令行敲下wrk,可以看到使用帮助
Usage: wrk
Options:
-c, --connections Connections to keep open
-d, --duration Duration of test
-t, --threads Number of threads to use
-s, --script Load Lua script file
-H, --header Add header to request
--latency Print latency statistics
--timeout Socket/request timeout
-v, --version Print version details
Numeric arguments may include a SI unit (1k, 1M, 1G)
Time arguments may include a time unit (2s, 2m, 2h)
简单翻成中文:
使用方法: wrk <选项> <被测HTTP服务的URL>
Options:
-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)
aaa_create.lua文件内容如下
request = function()
wrk.headers["cookie"] = 'aaaa';
wrk.headers["Content-Type"] = "application/json;charset=UTF-8"
wrk.headers["x-csrftoken"] = "75wTnK6TL85Nh5Pe0fhVTy8cpZQ"
wrk.body="{\"type\":1,\"status\":[1],\"from_time\":1546963200,\"to_time\":1547568000}"
-- Return current request url formated by wrk api
return wrk.format("POST", "/api/aaatask/create")
end
response = function(status, headers, body)
if status ~= 200 or string.find(body, "\"retcode\":0") == nil then
print("error", body)
else
print("right", body)
end
end
done = function(summary, latency, requests)
print("welcome to wrk!")
end
wrk -t10 -c10 -d5s --script=aaa_create.lua --latency https://www.aaa.com
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.44s 409.67ms 2.00s 65.79%
Req/Sec 0.03 0.18 1.00 96.74%
Latency Distribution
50% 1.55s
75% 1.73s
90% 1.89s
99% 2.00s
92 requests in 5.10s, 329.17KB read
Socket errors: connect 0, read 0, write 0, timeout 54
Requests/sec: 18.04
Transfer/sec: 64.53KB