WRK the HTTP benchmarking tool – Advanced Example

SSH Tunnel – Local and Remote Port Forwarding Explained With Examples
January 25, 2018
Monitoring
March 15, 2021

wrk is the HTTP benchmarking tool which combined with Lua scripts can be the bazooka in your benchmarking arsenal. This article shows an advanced example of using Lua scripts with wrk. I will also show you how to debug wrk.

First of all I would like to share the Docker awesomeness with you, so please make sure you have the following tools installed:

JSON File Example

The idea is very simple. We have an JSON file with request details and wrk will use this information in its benchmark. wrk doesn’t have this feature build in but we will use a Lua script to tell it what to do.

The JSON file might look like this:

[

  {

    “path”: “/path-1”,

    “body”: “some content”,

    “method”: “GET”,

    “headers”: {

      “X-Custom-Header-1”: “test 1”,

      “X-Custom-Header-2”: “test 2”

    }

  },

  {

    “path”: “/path-2”,

    “body”: “some content”,

    “method”: “POST”,

    “headers”: {

      “X-Custom-Header-1”: “test 3”,

      “X-Custom-Header-2”: “test 4”

    }

  }

]

As you can see each request has different properties.

Save it in the data directory as data/requests.json.

Now we need a proper lua script.

I prepared one below, save it as scripts/multi-request-json.lua:

— Module instantiation

local cjson = require “cjson”

local cjson2 = cjson.new()

local cjson_safe = require “cjson.safe”

— Initialize the pseudo random number generator

— Resource: http://lua-users.org/wiki/MathLibraryTutorial

math.randomseed(os.time())

math.random(); math.random(); math.random()

— Shuffle array

— Returns a randomly shuffled array

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

— Load URL paths from the file

function load_request_objects_from_file(file)

  local data = {}

  local content

  — Check if the file exists

  — Resource: http://stackoverflow.com/a/4991602/325852

  local f=io.open(file,”r”)

  if f~=nil then

    content = f:read(“*all”)

    io.close(f)

  else

    — Return the empty array

    return lines

  end

  — Translate Lua value to/from JSON

  data = cjson.decode(content)

  return shuffle(data)

end

— Load URL requests from file

requests = load_request_objects_from_file(“/data/requests.json”)

— Check if at least one path was found in the file

if #requests <= 0 then

  print(“multiplerequests: No requests found.”)

  os.exit()

end

print(“multiplerequests: Found ” .. #requests .. ” requests”)

— Initialize the requests array iterator

counter = 1

request = function()

  — Get the next requests array element

  local request_object = requests

  — Increment the counter

  counter = counter + 1

  — If the counter is longer than the requests array length then reset it

  if counter > #requests then

    counter = 1

  end

  — Return the request object with the current URL path

  return wrk.format(request_object.method, request_object.path, request_object.headers, request_object.body)

end

This script is extended with a shuffle functionality and instead of loading URL paths line by line we laod a JSON file. Parsing JSON requires a JSON library, which is loaded at the very top. This library transforms the request details from a JSON string into a Lua array.

The only thing that stops us from testing this example is the missing JSON library itself – we need to install it.

Let’s summarise: you need to save the JSON file as data/requests.json and the Lua script as scripts/multi-request-json.lua.

We will run wrk in a Docker container. This diagram will give you a good overview of how this is done:

Run the benchmark with:

docker run –rm \

           -v `pwd`/scripts:/scripts \

           -v `pwd`/data:/data \

           fg/wrk-json wrk -c1 -t1 -d5s -s /scripts/multi-request-json.lua http://$APPLICATION_IP:$APPLICATION_PORT

This command will pull the image from the public Docker registry. Then it executes the wrk command (inside the Docker container) which additionally takes the Lua script. The Lua script opens the /data/requests.json file, parses it and feeds wrk with the data. Everything is possible because we shared the appropriate direcotries with the Docker container by using the -v option.

The returned output might look like this:

multiplerequests: Found 2 requests

multiplerequests: Found 2 requests

Running 5s test @ http://10.135.232.163:3000

  1 threads and 1 connections

  Thread Stats   Avg      Stdev     Max   +/- Stdev

    Latency     1.32ms    1.41ms  18.91ms   91.81%

    Req/Sec     0.89k   304.69     1.47k    64.00%

  4447 requests in 5.00s, 0.85MB read

Requests/sec:    888.67

Transfer/sec:    174.44KB

Adding weights to this example could be also very easy: just duplicate the request objects or adjust the Lua script to recognize a weight property.

I hope that you liked this wrk and Lua example.

Leave a Reply

Your email address will not be published. Required fields are marked *