wrk -- 小巧轻盈的 http 性能测试工具.
- - 企业架构 - ITeye博客测试先行是软件系统质量保证的有效手段. 在单元测试方面, 我们有非常成熟的 xUnit 方案. 在集成测试方面, 我们 selenium 等自动化方案. 在性能测试方面也有很多成熟的工具, 比如 LoadRunner, Jmeter 等. 但是很多工具都是给专门的性能测试人员使用的, 功能虽然强大, 但是安装和操作不太方便.
git clone https://github.com/wg/wrk.git cd wrk make
wrk -t12 -c100 -d30s http://www.baidu.com
Running 30s test @ http://www.baidu.com 12 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 538.64ms 368.66ms 1.99s 77.33% Req/Sec 15.62 10.28 80.00 75.35% 5073 requests in 30.09s, 75.28MB read Socket errors: connect 0, read 5, write 0, timeout 64 Requests/sec: 168.59 Transfer/sec: 2.50MB
Thread Stats Avg Stdev Max +/- Stdev Latency 538.64ms 368.66ms 1.99s 77.33% Req/Sec 15.62 10.28 80.00 75.35%
5073 requests in 30.09s, 75.28MB read Socket errors: connect 0, read 5, write 0, timeout 64 Requests/sec: 168.59 Transfer/sec: 2.50MB
/wrk -t12 -c100 -d30s -T30s http://www.baidu.com
Running 30s test @ http://www.baidu.com 12 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 1.16s 1.61s 14.42s 86.52% Req/Sec 22.59 19.31 108.00 70.98% 4534 requests in 30.10s, 67.25MB read Requests/sec: 150.61 Transfer/sec: 2.23MB
wrk -t12 -c100 -d30s -T30s --latency http://www.baidu.com
Running 30s test @ http://www.baidu.com 12 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 1.22s 1.88s 17.59s 89.70% Req/Sec 14.47 9.92 98.00 77.06% Latency Distribution 50% 522.18ms 75% 1.17s 90% 3.22s 99% 8.87s 3887 requests in 30.09s, 57.82MB read Socket errors: connect 0, read 2, write 0, timeout 0 Requests/sec: 129.19 Transfer/sec: 1.92MB
wrk.method = "POST" wrk.body = "foo=bar&baz=quux" wrk.headers["Content-Type"] = "application/x-www-form-urlencoded"
wrk -t12 -c100 -d30s -T30s --script=post.lua --latency http://www.baidu.com
local wrk = { scheme = "http", host = "localhost", port = nil, method = "GET", path = "/", headers = {}, body = nil, thread = nil, }
function response(status, headers, body) if status ~= 200 then print(body) wrk.thread:stop() end end
done = function(summary, latency, requests) io.write("------------------------------\n") for _, p in pairs({ 50, 90, 99, 99.999 }) do n = latency:percentile(p) io.write(string.format("%g%%,%d\n", p, n)) end end
local counter = 1 local threads = {} function setup(thread) thread:set("id", counter) table.insert(threads, thread) counter = counter + 1 end function init(args) requests = 0 responses = 0 local msg = "thread %d created" print(msg:format(id)) end function request() requests = requests + 1 return wrk.request() end function response(status, headers, body) responses = responses + 1 end function 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)) end end
counter = 1 math.randomseed(os.time()) math.random(); math.random(); math.random() function file_exists(file) local f = io.open(file, "rb") if f then f:close() end return f ~= nil end function shuffle(paths) local j, k local n = #paths for i = 1, n do j, k = math.random(n), math.random(n) paths[j], paths[k] = paths[k], paths[j] end return paths end function non_empty_lines_from(file) if not file_exists(file) then return {} end lines = {} for line in io.lines(file) do if not (line == '') then lines[#lines + 1] = line end end return shuffle(lines) end paths = non_empty_lines_from("paths.txt") if #paths <= 0 then print("multiplepaths: No paths found. You have to create a file paths.txt with one path per line") os.exit() end print("multiplepaths: Found " .. #paths .. " paths") request = function() path = paths[counter] counter = counter + 1 if counter > #paths then counter = 1 end return wrk.format(nil, path) end
function getCookie(cookies, name) local start = string.find(cookies, name .. "=") if start == nil then return nil end return string.sub(cookies, start + #name + 1, string.find(cookies, ";", start) - 1) end response = function(status, headers, body) local token = getCookie(headers["Set-Cookie"], "token") if token ~= nil then wrk.headers["Cookie"] = "token=" .. token end end