同 ab 这种单线程 HTTP 性能测试工具相比,wrk 是一个足够现代化的 HTTP 性能测试工具,最重要的特性是:它是可编程的,借助内嵌 lua,我们可以控制测试的全过程。
关于 wrk 中 lua 扩展的数据结构,可以参考官方源代码中的 wrk.lua 文件:
local wrk = { scheme = "http", host = "localhost", port = nil, method = "GET", path = "/", headers = {}, body = nil, thread = nil, }
此外,还有一些钩子方法可供使用:
- setup(thread):启动阶段执行,每个线程调用一次
- init(args):运行阶段执行,每个线程调用一次
- delay(),运行阶段执行,每个请求调用一次
- request(),运行阶段执行,每个请求调用一次
- response(status, headers, body),运行阶段执行,每个请求调用一次
- done(summary, latency, requests),结束阶段执行,整个过程调用一次
多数情况下,我们只要关注 request 钩子方法即可,通过它我们可以自定义请求的各个参数,如果想要了解更多的用法,可以参考官方源代码的 scripts 目录。
让我们动手实战一下,假设一个网站,主要的请求有三种,分别是:
- /a:GET 请求,占比 20%
- /b:GET 请求,占比 30%
- /c:POST 请求,占比 50%
结合前面提到的 wrk 中 lua 扩展的相关知识,我们可以实现如下代码:
-- benchmark.lua math.randomseed(os.time()) local config = { {num=20, path="/a"}, {num=30, method="get", path="/b"}, {num=50, method="post", path="/c", body="foo=x&bar=y"}, } local requests = {} for i, request in ipairs(config) do if request.method then request.method = string.upper(request.method) end for _ = 1, request.num do requests[#requests + 1] = i end end local length = #requests for _ = 1, length do local m, n = math.random(length), math.random(length) requests[m], requests[n] = requests[n], requests[m] end local count = 0 function request() local i = (count % length) + 1 local request = config[requests[i]] count = count + 1 return wrk.format( request.method, request.path, request.headers, request.body ) end
代码逻辑很简单,无非就是根据配置信息生成一个大数组,然后把数据随机化一下,每个请求来的时候,根据计数器直接给一条数据即可。
我在我的笔记本上以此脚本为例实际跑了一个 100 并发的例子,这里有个题外话需要提一下,很多人做 benchmark 只关注 rps,却忽略了 latency,这是不严谨的,设想一个网站的 rps 数据很好,但是总有一定百分比的请求出现高 latency,依然是有问题的:
shell> wrk -c 100 -s ./benchmark.lua http://localhost Running 10s test @ http://localhost 2 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 4.26ms 1.04ms 23.95ms 94.87% Req/Sec 11.85k 662.52 13.08k 67.50% 235787 requests in 10.00s, 71.95MB read Non-2xx or 3xx responses: 0 Requests/sec: 23573.71 Transfer/sec: 7.19MB
在测试的时候我顺手用 ngrep 监控了一下请求:
如图可见,wrk 随机发送了不同的请求,完美!
评论前必须登录!
注册