WRK:一个可编程的HTTP性能测试工具

同 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 监控了一下请求:

ngrep -W byline '' 'dst port 80'

ngrep -W byline ” ‘dst port 80’

如图可见,wrk 随机发送了不同的请求,完美!

发表评论

电子邮件地址不会被公开。 必填项已用*标注