原文连贯: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 | 打印提早统计数据 |
--timeout | http 超时工夫 |
--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...