原文连贯:https://blog.fengjx.com/wrk/

wrk 是一个相似 ab(apache bench)、jmeter 的压力测试工具,底层基于 epoll 和 kqueue 实现,能充分利用服务器 cpu 资源,升高测试工具自身性能开销对测试后果准确性的影响。反对应用 lua 脚本自定义测试逻辑,应用上非常简单,但性能足够弱小。

没有理解过 lua 的同学,能够看下 lua 扼要教程 https://coolshell.cn/articles...

装置

  • linux https://github.com/wg/wrk/wik...
  • macOS https://github.com/wg/wrk/wik...
  • windows( Windows Subsystem for Linux ) https://github.com/wg/wrk/wik...

用法

$ wrk -hwrk: invalid option -- hUsage: wrk <options> <url>  Options:    -c, --connections <N>  Connections to keep open    -d, --duration    <T>  Duration of test    -t, --threads     <N>  Number of threads to use    -s, --script      <S>  Load Lua script file    -H, --header      <H>  Add header to request        --latency          Print latency statistics        --timeout     <T>  Socket/request timeout    -v, --version          Print version details
参数阐明
-c与服务器放弃的 http 连接数
-d压测工夫
-t应用线程数
-s自定义 lua 脚本门路
-H自定义 http header 申请头,例如:"User-Agent: benchmark-wrk"
--latency打印提早统计数据
--timeouthttp 超时工夫
--version打印版本信息

eg: wrk -t2 -c5 -d10s https://httpbin.org/get

这种状况只实用于每个申请都雷同的状况
$ wrk -t2 -c5 -d10s https://httpbin.org/getRunning 10s test @ https://httpbin.org/get  2 threads and 5 connections  Thread Stats   Avg      Stdev     Max   +/- Stdev    Latency   251.97ms   50.38ms 510.96ms   94.52%    Req/Sec     7.60      2.40    10.00     75.23%  146 requests in 10.05s, 61.17KB readRequests/sec:     14.52Transfer/sec:      6.08KB

编写 lua 测试脚本

官网文档:https://github.com/wg/wrk/blo...

编写 lua 脚本能够实现简单的测试场景,例如:须要登录认证的接口,查问不必 id 的数据(雷同 id 服务端可能有缓存,达不到实在压测成果)

先看官网一个简略的自定义脚本

wrk.method = "POST"wrk.body   = "foo=bar&baz=quux"wrk.headers["Content-Type"] = "application/x-www-form-urlencoded"
$ wrk -d3s -c2 -s scripts/post.lua https://httpbin.org/get

wrk 是一个内置的全局 table 类型变量,不须要定义能够间接应用,批改 wrk 变量的值,会对所有申请都失效。

wrk = {    scheme  = "http",    host    = "localhost",    port    = nil,    method  = "GET",    path    = "/",    headers = {},    body    = nil,    thread  = <userdata>}

wrk 内置函数

  • wrk.format

    function wrk.format(method, path, headers, body)

    wrk.format returns a HTTP request string containing the passed parameters
    merged with values from the wrk table.

    返回一个 http 申请字符串,参数会笼罩 wrk 全局配置,能够通过 format 能够结构出不同的 request

  • wrk.lookup

    function wrk.lookup(host, service)

    wrk.lookup returns a table containing all known addresses for the host
    and service pair. This corresponds to the POSIX getaddrinfo() function.

    返回所有可用服务器的地址信息

  • wrk.connect

    function wrk.connect(addr)

    wrk.connect returns true if the address can be connected to, otherwise
    it returns false. The address must be one returned from wrk.lookup().

    测试指定的服务器地址是否能失常连贯

    参考:

    local addrs = nilfunction setup(thread)  if not addrs then      addrs = wrk.lookup(wrk.host, wrk.port or "http")      for i = #addrs, 1, -1 do        if not wrk.connect(addrs[i]) then            table.remove(addrs, i)        end      end  end  thread.addr = addrs[math.random(#addrs)]end  function init(args)     local msg = "thread addr: %s"     print(msg:format(wrk.thread.addr))  end

生命周期回调函数

wrk 包含上面几个生命周期,在脚本中从新定义这些全局函数,能够批改 wrk 默认行为,实现个性化测试需要。

The following globals are optional, and if defined must be functions:

global setup    -- called during thread setupglobal init     -- called when the thread is starting,global delay    -- called to get the request delay,global request  -- called to generate the HTTP request,global response -- called with HTTP response data,global done     -- called with results of run

启动阶段

  • setup 每个线程初始化时执行一次

    function setup(thread)

    setup 办法会传入一个 thread 对象,能够批改或设置 thread 相干参数,也能够终止线程执行,这里个别做一些初始化的工作,例如读取配置文件,加载到内存,不要每次申请的时候读取一遍,这样对测试准确性影响很大

    thread.addr             - get or set the thread's server address,获取或设置服务器地址信息thread:get(name)        - get the value of a global in the thread's env,获取线程上下文参数thread:set(name, value) - set the value of a global in the thread's env,设置线程上下文参数thread:stop()           - stop the thread,终止线程

执行阶段

  • init 每个线程开始启动时执行一次

    function init(args)

    args 是通过命令行传入的参数,通过 -- 指定

    例如:wrk -d3s -c2 -s wrk.lua https://httpbin.org/get -- test 100

    function init(args)  for i, v in ipairs(args) do      print(i,v)  endend-- 输入-- 1    test-- 2    100
  • delay 每次发送申请时,间隔时间(ms),每次申请执行一次

    function delay()

    返回值决定每个申请距离

  • request 创立 request 时(发送 request 前)执行,每次申请执行一次

    function request()

    个别在这里会配合 wrk.format 办法,动态创建申请,这里不要执行耗时的代码,否则会影响测试后果准确性

  • response http 响应时执行,每次申请执行一次

    function response(status, headers, body)

    http 响应解决逻辑,参数对应 http 响应的 status, headers, body

    解析 header 和 body 的开销比拟大,所以如果没有定义 response 回调办法的话,wrk 就不会解析 header 和 body,这样测试后果会更加精确(解析响应数据是客户端负责的,不能算到服务器解决工夫外面)

完结阶段

  • done 返回后果时执行,整个测试过程只执行一次,能够生成自定义测试报告,如果没有特地需要,个别不重写这个办法

    function done(summary, latency, requests)

    参数含意

    latency.min              -- minimum value seenlatency.max              -- maximum value seenlatency.mean             -- average value seenlatency.stdev            -- standard deviationlatency:percentile(99.0) -- 99th percentile valuelatency(i)               -- raw value and countsummary = {  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  }}

官网示例

https://github.com/wg/wrk/blo...

local counter = 1local threads = {}function setup(thread)   thread:set("id", counter)   table.insert(threads, thread)   counter = counter + 1endfunction init(args)   requests  = 0   responses = 0   local msg = "thread %d created"   print(msg:format(id))endfunction request()   requests = requests + 1   return wrk.request()endfunction response(status, headers, body)   responses = responses + 1endfunction done(summary, latency, requests)   for index, thread in ipairs(threads) do      local id        = thread:get("id")      local requests  = thread:get("requests")      local responses = thread:get("responses")      local msg = "thread %d made %d requests and got %d responses"      print(msg:format(id, requests, responses))   endend

更多用法查看官网示例:https://github.com/wg/wrk/tre...