تخطَّ إلى المحتوى

wrk

wrk هي أداة حديثة لقياس أداء HTTP تستخدم تصميماً قائماً على الأحداث ومتعدد الخيوط لتوليد حمل كبير على خوادم الويب. تدعم برمجة Lua لإنشاء طلبات مخصصة ومعالجة الاستجابات وسيناريوهات اختبار معقدة.

التثبيت

# Ubuntu/Debian - build from source
sudo apt-get install build-essential libssl-dev git
git clone https://github.com/wg/wrk.git
cd wrk
make -j$(nproc)
sudo cp wrk /usr/local/bin/

# macOS
brew install wrk

# Verify installation
wrk --version

Basic Benchmarks

# Simple benchmark: 2 threads, 10 connections, 30 seconds
wrk -t2 -c10 -d30s http://localhost:8080/

# Higher load: 12 threads, 400 connections, 30 seconds
wrk -t12 -c400 -d30s http://localhost:8080/api/items

# Short burst test: 4 threads, 100 connections, 10 seconds
wrk -t4 -c100 -d10s http://localhost:8080/health

# With custom headers
wrk -t4 -c100 -d30s -H "Authorization: Bearer token123" \
    -H "Content-Type: application/json" \
    http://localhost:8080/api/data

Threads and Connections

# Thread and connection guidelines:
# - Threads (-t): usually match CPU cores (2-16)
# - Connections (-c): total concurrent connections across all threads
# - Each thread handles connections/threads connections

# Light load
wrk -t1 -c10 -d10s http://localhost:8080/

# Medium load
wrk -t4 -c100 -d30s http://localhost:8080/

# Heavy load
wrk -t8 -c500 -d60s http://localhost:8080/

# Maximum stress test
wrk -t12 -c1000 -d60s http://localhost:8080/

# Timeout per request (default: 2s)
wrk -t4 -c100 -d30s --timeout 5s http://localhost:8080/

Duration الخيارات

# Seconds
wrk -t4 -c100 -d30s http://localhost:8080/

# Minutes
wrk -t4 -c100 -d5m http://localhost:8080/

# With latency distribution breakdown
wrk -t4 -c100 -d30s --latency http://localhost:8080/
# Shows 50%, 75%, 90%, 99% percentile latencies

Reading المخرجات

# Example wrk output:
# Running 30s test @ http://localhost:8080/
#   4 threads and 100 connections
#   Thread Stats   Avg      Stdev     Max   +/- Stdev
#     Latency     5.23ms    2.41ms  48.32ms   78.15%
#     Req/Sec     4.87k   312.45     6.12k    71.25%
#   Latency Distribution
#     50%    4.82ms
#     75%    6.15ms
#     90%    8.23ms
#     99%   14.51ms
#   582341 requests in 30.01s, 1.23GB read
# Requests/sec:  19405.12
# Transfer/sec:     42.01MB

# Key metrics:
# Latency Avg - average response time
# Req/Sec - requests per second per thread
# Requests/sec - total throughput
# Non-2xx or 3xx responses - errors (shown if any)

Lua Scripting

Custom Request Generation

-- post.lua - Send POST requests with JSON body
wrk.method = "POST"
wrk.body   = '{"username": "test", "action": "login"}'
wrk.headers["Content-Type"] = "application/json"
# Run with Lua script
wrk -t4 -c100 -d30s -s post.lua http://localhost:8080/api/login

Dynamic Request Bodies

-- dynamic.lua - Generate unique requests per thread
local counter = 0
local threads = {}

function setup(thread)
    table.insert(threads, thread)
    thread:set("id", counter)
    counter = counter + 1
end

function init(args)
    requests = 0
    local id = wrk.thread:get("id")
end

function request()
    requests = requests + 1
    local body = string.format('{"id": %d, "seq": %d}', wrk.thread:get("id"), requests)
    return wrk.format("POST", "/api/items", {
        ["Content-Type"] = "application/json"
    }, body)
end

Response Processing

-- response.lua - Process and log responses
local responses = {}

function response(status, headers, body)
    if responses[status] == nil then
        responses[status] = 0
    end
    responses[status] = responses[status] + 1
end

function done(summary, latency, requests)
    io.write("Status code distribution:\n")
    for status, count in pairs(responses) do
        io.write(string.format("  [%d] %d responses\n", status, count))
    end

    io.write(string.format("\nLatency percentiles:\n"))
    for _, p in pairs({50, 75, 90, 99, 99.9}) do
        io.write(string.format("  %5.1f%%: %s\n", p,
            tostring(latency:percentile(p) / 1000) .. "ms"))
    end

    io.write(string.format("\nTotal requests: %d\n", summary.requests))
    io.write(string.format("Total errors:   %d\n", summary.errors.status))
end

Request Pipeline

-- pipeline.lua - HTTP pipelining (multiple requests per connection)
init = function(args)
    local r = {}
    -- Pipeline 10 requests at a time
    for i = 1, 10 do
        r[i] = wrk.format("GET", "/api/item/" .. i)
    end
    req = table.concat(r)
end

request = function()
    return req
end

المصادقة Flow

-- auth.lua - Authenticate first, then benchmark
local token = nil

function setup(thread)
    -- This runs once per thread
end

function init(args)
    -- Authenticate to get a token
    local headers = {["Content-Type"] = "application/json"}
    local body = '{"username": "loadtest", "password": "test123"}'
    -- Token would be set from response in a real scenario
    token = "Bearer test-token-123"
end

function request()
    return wrk.format("GET", "/api/protected", {
        ["Authorization"] = token,
        ["Accept"] = "application/json"
    })
end

wrk2 Variant

# wrk2 adds constant-throughput rate limiting
# Install wrk2
git clone https://github.com/giltene/wrk2.git
cd wrk2
make -j$(nproc)
sudo cp wrk /usr/local/bin/wrk2

# Run with target rate (requests/second)
wrk2 -t4 -c100 -d60s -R2000 http://localhost:8080/
# -R2000 = target 2000 requests per second

# wrk2 provides more accurate latency measurements
# by avoiding coordinated omission problem

# Compare wrk vs wrk2:
# wrk  = open-loop (as fast as possible)
# wrk2 = closed-loop (constant rate, better latency stats)

Common Test Patterns

# Quick smoke test
wrk -t1 -c1 -d5s http://localhost:8080/health

# Baseline performance
wrk -t2 -c10 -d30s --latency http://localhost:8080/

# Connection scaling test (run multiple times, increase -c)
for c in 10 50 100 200 500 1000; do
    echo "=== $c connections ==="
    wrk -t4 -c$c -d15s --latency http://localhost:8080/
    sleep 2
done

# Compare endpoints
for endpoint in /api/v1/users /api/v1/items /api/v1/search; do
    echo "=== $endpoint ==="
    wrk -t4 -c100 -d30s --latency http://localhost:8080$endpoint
done

نصائح

# Check system limits before high-connection tests
ulimit -n  # Open files limit
# Increase if needed
ulimit -n 65535

# Monitor server during benchmarks
# (in another terminal)
watch -n1 'ss -s'  # Socket statistics
vmstat 1            # System stats