Table of Contents

Overview

wrk is a modern HTTP benchmarking tool capable of generating significant load using a single multi-core CPU. It combines a multithreaded design with scalable event notification systems.

Key Features

  • HTTP/HTTPS testing
  • Lua scripting support
  • Multiple threads
  • Connection keep-alive
  • Custom headers
  • Request generation
  • Response handling
  • Detailed statistics

Installation

Ubuntu (22.04/24.04)

# Install dependencies
sudo apt install build-essential libssl-dev git
 
# Clone and build
git clone https://github.com/wg/wrk.git
cd wrk
make
sudo cp wrk /usr/local/bin

macOS

# Using Homebrew
brew install wrk

Basic Usage

Simple Benchmarks

# Basic test (default: 2 threads, 10 connections, 10s)
wrk http://localhost:8080/
 
# Specify duration
wrk -d 30s http://localhost:8080/
 
# Custom threads and connections
wrk -t12 -c400 -d30s http://localhost:8080/

Connection Options

# Keep-alive connections
wrk -t2 -c100 -d30s --latency http://localhost:8080/
 
# Disable keep-alive
wrk -t2 -c100 -d30s --timeout 2s http://localhost:8080/

Advanced Options

Headers and Methods

# Add headers
wrk -H "Accept-Encoding: gzip" http://localhost:8080/
 
# Multiple headers
wrk -H "Authorization: Bearer token" \
    -H "Content-Type: application/json" \
    http://localhost:8080/
 
# Specify HTTP method
wrk -s post.lua http://localhost:8080/

Timeout and Rates

# Set timeout
wrk -t2 -c100 -d30s --timeout 30s http://localhost:8080/
 
# Limit request rate
wrk -t2 -c100 -d30s --rate 1000 http://localhost:8080/
 
# Connection timeout
wrk -t2 -c100 -d30s --connect-timeout 5s http://localhost:8080/

Scripting

Basic Lua Script

-- request.lua
wrk.method = "POST"
wrk.body   = '{"key": "value"}'
wrk.headers["Content-Type"] = "application/json"

Advanced Scripts

-- advanced.lua
counter = 0
request = function()
   path = "/item/" .. counter
   counter = counter + 1
   return wrk.format("GET", path)
end
 
response = function(status, headers, body)
   if status ~= 200 then
      print("Error: " .. status)
   end
end

Random Data

-- random.lua
math.randomseed(os.time())
request = function()
   id = math.random(1, 100)
   path = "/api/items/" .. id
   return wrk.format("GET", path)
end

Results Analysis

Understanding Output

Running 30s test @ http://localhost:8080/
  12 threads and 400 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    45.12ms   23.45ms  123.45ms   70.25%
    Req/Sec     1.23k   145.23     1.45k    75.00%
  70234 requests in 30.01s, 10.25MB read
  Socket errors: connect 0, read 0, write 0, timeout 12
Requests/sec:   2341.23
Transfer/sec:    349.23KB

Custom Reporting

-- report.lua
done = function(summary, latency, requests)
   io.write("------------------------------\n")
   io.write("Test Summary:\n")
   io.write(string.format("  Requests/sec: %.2f\n", requests.rate))
   io.write(string.format("  Transfer/sec: %.2f\n", requests.bytes))
   io.write(string.format("  Avg Latency: %.2fms\n", latency.mean))
   io.write("------------------------------\n")
end

Best Practices

Load Testing Guidelines

# Warm-up run
wrk -t2 -c10 -d10s http://localhost:8080/
 
# Gradual load increase
wrk -t2 -c100 -d30s http://localhost:8080/
wrk -t4 -c200 -d30s http://localhost:8080/
wrk -t8 -c400 -d30s http://localhost:8080/

Resource Management

# Monitor system resources
vmstat 1
 
# Watch network connections
watch -n1 'netstat -an | grep ESTABLISHED | wc -l'
 
# Monitor target system
top -b -n 1

Common Scenarios

REST API Testing

-- api_test.lua
wrk.method = "POST"
wrk.body   = '{"username": "test", "password": "test123"}'
wrk.headers["Content-Type"] = "application/json"
wrk.headers["Authorization"] = "Bearer token"

Load Testing with Authentication

-- auth_test.lua
token = nil
 
setup = function(thread)
   -- Perform login and get token
   local auth_body = '{"username":"test","password":"test123"}'
   local auth_headers = "Content-Type: application/json"
   -- Store token for requests
   token = "Bearer " .. response.token
end
 
request = function()
   return wrk.format("GET", "/api/data", {
      ["Authorization"] = token,
      ["Content-Type"] = "application/json"
   })
end

Performance Testing

-- performance.lua
requests = 0
errors = 0
 
request = function()
   requests = requests + 1
   return wrk.format("GET", "/")
end
 
response = function(status, headers, body)
   if status ~= 200 then
      errors = errors + 1
   end
end
 
done = function(summary, latency, requests)
   io.write(string.format("Requests: %d\n", requests))
   io.write(string.format("Errors: %d\n", errors))
end

Quick Reference

Essential Commands

# Basic test
wrk -t2 -c100 -d30s http://localhost:8080/
 
# With script
wrk -t2 -c100 -d30s -s script.lua http://localhost:8080/
 
# With headers
wrk -H "Key: Value" http://localhost:8080/
 
# With latency stats
wrk --latency http://localhost:8080/

Common Options

-c    # Connections to keep open
-d    # Duration of test
-t    # Number of threads to use
-s    # Load Lua script
-H    # Add header
--latency    # Print detailed latency statistics
--timeout    # Socket/request timeout

Example Scripts

Basic POST Request

-- post.lua
wrk.method = "POST"
wrk.body   = '{"test": "data"}'
wrk.headers["Content-Type"] = "application/json"

Random Path Generator

-- random_path.lua
paths = {"/api/v1/users", "/api/v1/items", "/api/v1/orders"}
 
request = function()
   local path = paths[math.random(#paths)]
   return wrk.format("GET", path)
end

Remember:

  • Start with lower loads
  • Monitor system resources
  • Analyze results carefully
  • Consider target system capacity
  • Document test scenarios
  • Use appropriate timeouts

For detailed information, consult the wrk GitHub repository and documentation.