Master HTTP Load Testing with wrk: Install, Commands, and Lua Scripting
This guide walks you through installing the wrk load‑testing tool on Unix‑like systems, explains its core command‑line options, shows how to interpret benchmark results, and demonstrates advanced customization using Lua scripts for POST requests, dynamic parameters, authentication, and HTTP pipelining.
Having tried many load‑testing tools without finding a favorite, I tested wrk and found it useful, so I wrote this usage guide as a personal reference that may also help others.
Installation
wrk runs on most Unix‑like systems (not Windows) and requires LuaJIT and OpenSSL support, which are available on most platforms. Install it by cloning the source from GitHub and running make in the project directory.
git clone https://github.com/wg/wrk
makeAfter make, the executable wrk appears in the current directory. Copy it to a directory in your PATH (e.g., /usr/local/bin) to run it from anywhere.
If you prefer to use the system‑installed LuaJIT and OpenSSL, specify their locations with the WITH_LUAJIT and WITH_OPENSSL options, for example:
make WITH_LUAJIT=/usr WITH_OPENSSL=/usrBasic Usage
Run wrk without arguments to see the help message.
Usage: 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
Numeric arguments may include SI units (1k, 1M, 1G).
Time arguments may include a time unit (2s, 2m, 2h).In Chinese the options are:
使用方法: wrk <选项> <被测HTTP服务的URL>
Options:
-c, --connections <N> 跟服务器建立并保持的TCP连接数量
-d, --duration <T> 压测时间
-t, --threads <N> 使用多少个线程进行压测
-s, --script <S> 指定Lua脚本路径
-H, --header <H> 为每一个HTTP请求添加HTTP头
--latency 在压测结束后,打印延迟统计信息
--timeout <T> 超时时间
-v, --version 打印正在使用的wrk的详细版本信息Check the version:
wrk -v
输出:
wrk 4.0.2 [epoll] Copyright (C) 2012 Will GlozerThe output shows wrk 4.0.2 compiled with epoll, meaning it can create many connections with few threads.
Run a simple benchmark and analyze the result:
wrk -t8 -c200 -d30s --latency "http://www.bing.com"
输出:
Running 30s test @ http://www.bing.com
8 threads and 200 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 46.67ms 215.38ms 1.67s 95.59%
Req/Sec 7.91k 1.15k 10.26k 70.77%
Latency Distribution
50% 2.93ms
75% 3.78ms
90% 4.73ms
99% 1.35s
1790465 requests in 30.01s, 684.08MB read
Requests/sec: 59658.29
Transfer/sec: 22.79MBThe benchmark used 8 threads and 200 connections for 30 seconds against Bing's homepage, printing latency statistics. Key points:
Running 30s test @ http://www.bing.com (压测时间30s)
8 threads and 200 connections (共8个测试线程,200个连接)
Thread Stats Avg Stdev Max +/- Stdev
Latency 46.67ms 215.38ms 1.67s 95.59% (延迟)
Req/Sec 7.91k 1.15k 10.26k 70.77% (处理中的请求数)
Latency Distribution (延迟分布)
50% 2.93ms
75% 3.78ms
90% 4.73ms
99% 1.35s (99分位的延迟)
1790465 requests in 30.01s, 684.08MB read (30.01秒内共处理完成了1790465个请求,读取了684.08MB数据)
Requests/sec: 59658.29 (平均每秒处理完成59658.29个请求)
Transfer/sec: 22.79MB (平均每秒读取数据22.79MB)wrk is easy to use, produces clear results, and thanks to its non‑blocking I/O can generate many connections on a modest machine.
Customizing wrk with Lua Scripts
Simple tests may not meet all scenarios. wrk allows a Lua script (specified with --script) to customize the load test, enabling POST methods, dynamic parameters, authentication, and HTTP pipelining.
Lua script support overview
wrk provides three hook phases: setup (executed once per thread before it starts), init/delay/request/response (executed during the run), and done (executed once after the test).
Setup Phase
function setup(thread)The setup function runs after a thread is created but before it starts. It receives a thread object that can be inspected or modified.
thread.addr -- get or set the thread's server address
thread:get(name) -- get a global variable in the thread's env
thread:set(name, val) -- set a global variable in the thread's env
thread:stop() -- stop the threadRun Phase
function init(args)
function delay()
function request()
function response(status, headers, body) initruns once per thread at the start of the run and can read command‑line arguments. delay is called before each request; returning a number inserts that many milliseconds of pause. request must return the HTTP request string and is called for every request. response is invoked for each response; omitting it skips header/body parsing for speed.
Done Phase
function done(summary, latency, requests)Called once after the whole test, allowing custom reporting based on the provided summary objects.
Accessible Variables and Methods
The global wrk table holds request defaults:
wrk = {
scheme = "http",
host = "localhost",
port = nil,
method = "GET",
path = "/",
headers = {},
body = nil,
thread = <userdata>
}Modifying this table affects all generated requests. Useful functions include wrk.format, wrk.lookup, and wrk.connect:
function wrk.format(method, path, headers, body)
-- returns an HTTP request string merged with values from the wrk table
end
function wrk.lookup(host, service)
-- returns a table of all known addresses for the host/service pair (POSIX getaddrinfo)
end
function wrk.connect(addr)
-- returns true if the address can be connected, false otherwise
endExamples
Using POST Method
wrk.method = "POST"
wrk.body = "foo=bar&baz=quux"
wrk.headers["Content-Type"] = "application/x-www-form-urlencoded"All requests will now use POST with the specified body and header.
Randomizing a Parameter per Request
request = function()
uid = math.random(1, 10000000)
path = "/test?uid=" .. uid
return wrk.format(nil, path)
endThis generates a random uid between 1 and 10,000,000 for each request.
Adding a 10 ms Delay Before Each Request
function delay()
return 10
endAuthentication Followed by Token‑Based Requests
token = nil
path = "/authenticate"
request = function()
return wrk.format("GET", path)
end
response = function(status, headers, body)
if not token and status == 200 then
token = headers["X-Token"]
path = "/resource"
wrk.headers["X-Token"] = token
end
endThe script first calls /authenticate, extracts the X-Token header, then switches to /resource with the token attached.
Testing an HTTP‑Pipeline‑Enabled Service
init = function(args)
local r = {}
r[1] = wrk.format(nil, "/?foo")
r[2] = wrk.format(nil, "/?bar")
r[3] = wrk.format(nil, "/?baz")
req = table.concat(r)
end
request = function()
return req
endThe init function concatenates three request strings, so each call to request sends them together, exercising HTTP pipelining.
Conclusion
The source code of wrk is concise; reading it gives a strong appreciation for its design and the author's skill.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
MaGe Linux Operations
Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
