介绍分为四部分
1.wrk简述
2.wrk安装
3.wrk运行参数
4.wrk高级用法
1.wrk简述
当使用ab做压测的时候发现,ab的客户端消耗很大,而且测试时性能较差,测试redis,spring boot时性能都与官方介绍相差太多,由此引入wrk.
wrk是一款简单的HTTP压测工具,托管在Github上, https://github.com/wg/wrk.
wrk 的一个很好的特性就是能用很少的线程压出很大的并发量. 原因是它使用了一些操作系统特定的高性能 io 机制, 比如 select, epoll, kqueue 等. 其实它是复用了 redis 的 ae 异步事件驱动框架. 确切的说 ae 事件驱动框架并不是 redis 发明的, 它来至于 Tcl的解释器 jim, 这个小巧高效的框架, 因为被 redis 采用而更多的被大家所熟知.
wrk 的一个很好的特性就是能用很少的线程压出很大的并发量. 原因是它使用了一些操作系统特定的高性能 io 机制, 比如 select, epoll, kqueue 等. 其实它是复用了 redis 的 ae 异步事件驱动框架. 确切的说 ae 事件驱动框架并不是 redis 发明的, 它来至于 Tcl的解释器 jim, 这个小巧高效的框架, 因为被 redis 采用而更多的被大家所熟知.
wrk源码涉及到很多系统内核的调用,指望另有大神阅读并出示解释,引用一篇:https://blog.csdn.net/codingwithme/article/details/52251451
2.wrk安装
在mac上可以使用brew安装:
brew install wrk
也可以使用源码安装:
git clone https://github.com/wg/wrk.git
cd wrk
make
3.wrk运行参数
wrk常规操作:
wrk -t15 -c300 -d10 --latency -s generateIDCode.lua http://localhost:14077/test
-t : thread 开启线程数
-c : connection 服务端连接数
-d : during 测试时间
—latency : 显示时延分布
结果如下:
Running 10s test @ http://10.1.4.55:14077/test
15 threads and 300 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 5.89ms 12.65ms 244.40ms 98.05%
Req/Sec 4.40k 0.86k 6.15k 82.42%
Latency Distribution
50% 3.88ms
75% 5.59ms
90% 8.28ms
99% 31.96ms
657863 requests in 10.10s, 53.33MB read
Requests/sec: 65137.56
Transfer/sec: 5.28MB
这里面比较复杂的是lua脚本的编写,正常http,post访问需要提供一份lua脚本:
wrk.method = "POST"
wrk.headers["Content-Type"] = "application/json"
wrk.body = '{"header": {"requestTime": "2018100910320000","requestSeq": "e379853d-d93e-4249-b9be-8a272b","appId": "bc1f4a2a995b47db9018031801984857"},"content": {"duration": "300","idCard": "350123199502150000sfsdafwjdhsjofwofnsdfnjdwfnew1561651dsfsdnklndsjfn1165165165fdsfhweufwehfjdsnfiefenf350123199502150000sfsdafwjdhsjofwofnsdfnjdwfnew1561651dsfsdnklndsjfn1165165165fdsfhweufwehfjdsnfiefenf350123199502150000","expressParam": "expressParamexpressParaexpres","name": "name","isPic": "0","availableTimes": "5"}}'
到这里就满足大多数情况的压测使用了.只不过我们习惯性拓展一下:
这里要记录wrk用这种方式提供了哪些可自定义的东西
变量值:
wrk = {
scheme = "http",
host = "localhost",
port = nil,
method = "GET",
path = "/",
headers = {},
body = nil,
thread = <userdata>,
}
方法:
-- 生成整个request的string,例如:返回
-- GET / HTTP/1.1
-- Host: tool.lu
function wrk.format(method, path, headers, body) -- 获取域名的IP和端口,返回table,例如:返回 `{127.0.0.1:80}`
function wrk.lookup(host, service) -- 判断addr是否能连接,例如:`127.0.0.1:80`,返回 true 或 false
function wrk.connect(addr) function setup(thread) -- thread提供了1个属性,3个方法
-- thread.addr 设置请求需要打到的ip
-- thread:get(name) 获取线程全局变量
-- thread:set(name, value) 设置线程全局变量
-- thread:stop() 终止线程 function init(args)
-- 每个线程仅调用1次,args 用于获取命令行中传入的参数, 例如 --env=pre function delay()
-- 每个线程调用多次,发送下一个请求之前的延迟, 单位为ms function request()
-- 每个线程调用多次,返回http请求 function response(status, headers, body)
-- 每个线程调用多次,返回http响应 function done(summary, latency, requests) latency.min -- minimum value seen
latency.max -- maximum value seen
latency.mean -- average value seen
latency.stdev -- standard deviation
latency:percentile(99.0) -- 99th percentile value
latency(i) -- raw value and count summary = {
duration = N, -- run duration in microseconds
requests = N, -- total completed requests
bytes = N, -- total bytes received
errors = {
connect = N, -- total socket connection errors
read = N, -- total socket read errors
write = N, -- total socket write errors
status = N, -- total HTTP status codes > 399
timeout = N -- total request timeouts
}
}
4.wrk高级用法
两个例子:例子是网上找的,但是这两个功能是最实用的,其他方法变量用到的场景都比较少:
1.请求时,打印response内容:
function response(status, headers, body)
print(body)
end
2.请求时,构造变动的随机id:
request = function()
counter = counter + 1
local task_id = string.format("%d-%s", os.time()*10000+math.random(1, 10000), randomString(10)) local data = [[{
"task_timeout": 30,
"task_id": "%s",
"task_body": {
"url_list": [
{
"subtask_id": "1000000022511092",
"url": "http://zhihu.com/upic/2017/08/24/15/kk.webp",
"force": true
},
{
"subtask_id": "1000000022511093",
"url": "http://zhihu.com/upic/2017/08/24/15/zz.jpg",
"force": true
}
]
},
"ip_list": [],
"ip_list_flag": false,
"task_type": "refresh",
"retry_failed": false,
"working_layer": "polymerization"
}]] wrk.method = "POST"
wrk.body = string.format(data, tostring(task_id))
wrk.headers["Content-Type"] = "application/json"
-- return wrk.format("POST", "/v1/engine/task")
return wrk.format() end
以及:
local queries = {
"language=php",
"language=java",
"language=lua"
}
local i =
request = function()
local body = wrk.format(nil, nil, nil, queries[i % #queries + ])
i = i +
return body
end