wrk压测工具使用
介绍分为四部分
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源码涉及到很多系统内核的调用,指望另有大神阅读并出示解释,引用一篇:https://blog.csdn.net/codingwithme/article/details/52251451wrk 的一个很好的特性就是能用很少的线程压出很大的并发量. 原因是它使用了一些操作系统特定的高性能 io 机制, 比如 select, epoll, kqueue 等. 其实它是复用了 redis 的 ae 异步事件驱动框架. 确切的说 ae 事件驱动框架并不是 redis 发明的, 它来至于 Tcl的解释器 jim, 这个小巧高效的框架, 因为被 redis 采用而更多的被大家所熟知.
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 = 0 request = function() local body = wrk.format(nil, nil, nil, queries[i % #queries + 1]) i = i + 1 return body end