ベンチマークツール"wrk"で自由にリクエストを送る

  • 41
    Like
  • 0
    Comment
More than 1 year has passed since last update.

「Apache Benchと同じくらい簡単に使えてもうちょっと色々出来るベンチマークツールが欲しい!」と思って探していたら良さそうなベンチマークツールが公開されてた。

wg/wrk - GitHub

Luaで簡単に動作を拡張できるらしい。ナウい。

使い方

普通にリクエストする分にはabとあんまり変わらない。

# コネクション4つ, スレッド2つで1秒間
wrk -c 4 -t 2 -d 1 http://hogehogedondon.net

スクリプトで動作を拡張する

ドキュメントとサンプルは以下

wrk/SCRIPTING at master · wg/wrk · GitHub
wrk/scripts at master · wg/wrk · GitHub

-sオプションでLuaのファイルを渡せば実行できる。

# コネクション4つ, スレッド2つで1秒間
wrk -c 4 -t 2 -d 1 -s ./wrk.lua http://hogehogedondon.net

サンプルの中には、例えばPOSTリクエストでベンチマークするためのスクリプトがある。

wrk/post.lua at master · wg/wrk · GitHub

post.lua
-- example HTTP POST script which demonstrates setting the
-- HTTP method, body, and adding a header

wrk.method = "POST"
wrk.body   = "foo=bar&baz=quux"
wrk.headers["Content-Type"] = "application/x-www-form-urlencoded"

かなり簡単。
単純にmethodやbodyを変更できる他、init関数やrequest関数, response関数を定義しておけばそれぞれベンチマーク開始時,リクエスト前,リクエスト後に任意の処理を挟めるようになる。

スクリプトについてもっと詳しく

wrkは実行中、リクエスト先のホスト名やパスの情報をテーブルにして持っている。

wrk/wrk.lua at master · wg/wrk · GitHub

wrk.lua
local wrk = {
   scheme  = "http",
   host    = "localhost",
   port    = nil,
   method  = "GET",
   path    = "/",
   headers = {},
   body    = nil,
   thread  = nil,
}

リクエストを送る際は、このテーブルの内容を元に同ファイルに定義されているwrk.format関数でデータを組み立てる。
この関数は引数で受け取ったメソッドやらパスやらをテーブルの値とマージして、HTTP用の文字列を返す。

ユーザーがrequest関数を定義しない場合、wrk.format関数を呼び出してその戻り値を返すだけのデフォルトの実装が使用される。

wrk/wrk.lua#L44 at master · wg/wrk · GitHub

wrk.lua
function wrk.init(args)
   ・
   ・
   ・
   local req = wrk.format()
   wrk.request = function()
      return req
   end
end

自分でrequest関数を書く場合も、ほとんどの場合最終的にwrk.format関数の戻り値を返すような実装になるはず(自分でHTTPに則った文字列を構成することもできそうだけど)
その場合は最良のベンチマーク結果を得るため、init関数で予めリクエスト内容の一覧(wrk.format関数の戻り値の一覧)を生成しておく等の対応が推奨されている。

request() returns a string containing the HTTP request. Building a new
request each time is expensive, when testing a high performance server
one solution is to pre-generate all requests in init() and do a quick
lookup in request().
wrk/SCRIPTING#L81 at master · wg/wrk · GitHub

書く

例えば"ファイルに定義されたパスに対してランダムにリクエストを送る”というような処理が簡単に書ける。

local requests = { }
local total = 0

init = function(args)
   wrk.headers["User-Agent"] = "wrk benchmark tool"

   local f = io.open("paths.txt", "r")
   for path in f:lines() do
      table.insert(requests, wrk.format(nil, path))
   end
   f:close()

   total = table.maxn(requests)
end

request = function()
   local n = math.random(total)
   return requests[n]
end

response関数を定義すればレスポンスのbody等が取得できるので、例えば"レスポンスのhtmlをパースしてその中の特定のリンクを次のリクエスト先とする"みたいな処理を書くのも難しくなさそう。