HTTP ベンチマークツール wrk についてメモ

モダンな HTTP ベンチマークツール wkr の簡単な使い方についてメモ。

wrk の特徴は以下。

  • C で書かれている
  • マルチコア CPU を 活かした高負荷をかけられる
  • スレッドと epoll/kqueue のイベントドリブンを活用して負荷をスケールさせる(NOTICE ファイルを読むと Redis Event Library(ae event loop) を拝借しているようです)
  • Lua スクリプトで HTTP クライアントの処理や実行結果のレポートをカスタマイズできる

Installing wrk in CentOS 6

まずはビルドに必要なパッケージをインストールします。

$ sudo yum install git
$ sudo yum groupinstall 'Development Tools'
$ sudo yum install openssl-devel

openssl-devel をインストールしていないと、make 時に以下のようなエラーが発生します。

In file included from src/wrk.c:3:
src/wrk.h:11:25: error: openssl/ssl.h: No such file or directory
src/wrk.h:12:25: error: openssl/err.h: No such file or directory

次にソースコードから wrk をビルドします。

$ git clone https://github.com/wg/wrk.git
Initialized empty Git repository in /root/wrk/.git/
remote: Counting objects: 792, done.
remote: Total 792 (delta 0), reused 0 (delta 0), pack-reused 792
Receiving objects: 100% (792/792), 1.12 MiB | 147 KiB/s, done.
Resolving deltas: 100% (430/430), done.
$ cd wrk/
$ make
...
$ ls -1
CHANGES
LICENSE
Makefile
NOTICE
README
SCRIPTING
deps
obj
scripts
src
wrk <- Compiled Binary

Usage

$ ./wrk --help
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 a SI unit (1k, 1M, 1G)
  Time arguments may include a time unit (2s, 2m, 2h)
$ ./wrk -t12 -c400 -d30s -H"User-Agent: MyBrowser" --latency --timeout 5 http://127.0.0.1:80/index.html
Running 30s test @ http://127.0.0.1:80/index.html
  12 threads and 400 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   218.81ms  474.65ms   4.64s    85.41%
    Req/Sec     1.20k     1.09k    7.99k    83.74%
  Latency Distribution
     50%  247.00us
     75%   12.20ms
     90%  999.45ms
     99%    1.81s
  249092 requests in 30.10s, 201.67MB read
  Socket errors: connect 0, read 28, write 0, timeout 25
Requests/sec:   8275.51
Transfer/sec:      6.70MB

上の例では

  • 12 スレッド(-t12)
  • 同時 400 コネクション(-c400)
  • 負荷は 30 秒かける(-d30s)
  • リクエストヘッダー “User-Agent: MyBrowser” を送信(-H"User-Agent: MyBrowser")
  • 通信は5秒でタイムアウト(--timeout 5)
  • ベンチマーク結果にレイテンシの統計情報も表示(--Latency)
  • リクエスト先は http://127.0.0.1:80/index.html

というようになっています。

wrk scripting

wrk は Lua スクリプトで

  • setup フェーズ(スレッド単位のカスタマイズ)
  • running フェーズ(リクエスト単位のカスタマイズ)
  • done フェーズ(レポート処理)

の各フェーズで処理やグローバル変数をカスタマイズできます。

実行環境はスレッドごとに独立しています

Lua スクリプトの詳細は次のファイルを参照

https://github.com/wg/wrk/blob/master/SCRIPTING

Lua スクリプト読み込み例

$ wrk -s /path/to/program.lua URL

というように -s オプションで指定します。
複数指定した場合、一番最後のスクリプトが利用される模様。

サンプルスクリプトの説明

ソースコードの wrk/scripts 以下にサンプルコードが転がっているので、各スクリプトを手短に解説します。
特に次の2つが参考になるかと思います。

  • post.lua
  • setup.lua

addr.lua

wrk.lookup(POSIX getaddrinfo に相当) を setup フェーズで実行し、接続先ホストの IP アドレスをランダムに決定する例
ホストに複数の IP が割り当てられていないと意味を成さない。

auth.lua

running フェーズで response 変数を使い、レスポンスヘッダーの特定のフィールドを次回以降のリクエストで活用する例。

counter.lua

running フェーズで request 関数を使い、リクエストごとにカウンターをインクレメントしてリクエストヘッダーに渡す例

delay.lua

running フェーズで delay 関数を使い、リクエスト前にランダムに遅延を発生させる例。

pipeline.lua

running フェーズで init 関数を使い、HTTP パイプラインする例。

https://en.wikipedia.org/wiki/HTTP_pipelining

post.lua

連想配列(Lua で言うところの Table) を書き換えて、HTTPリクエストのリクエストに含まれる

  • Method
  • Body
  • Request Header

を書き換える例。
コマンドラインからは GET メソッドで URL しか渡せないので、実試験では重宝します。

report.lua

done フェーズで done 関数を使い、実行結果をカスタマイズする例。

setup.lua

一番参考にすべき例。
setup/running/done のすべてのフェーズをカスタマイズ。
スレッドごとに番号を振り、running フェーズでリクエスト数をカウントし、done フェーズでスレッド単位の総リクエスト数を出力。

$ ./wrk -s ./scripts/setup.lua -c3 -d 3s -t 3 http://localhost:80/index.html
thread 1 created
thread 2 created
thread 3 created
Running 3s test @ http://localhost:80/index.html
  3 threads and 3 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     2.47ms    4.19ms  28.29ms   84.44%
    Req/Sec     2.94k   618.72     4.64k    65.56%
  26510 requests in 3.04s, 21.46MB read
Requests/sec:   8732.85
Transfer/sec:      7.07MB
thread 1 made 9130 requests and got 9128 responses
thread 2 made 8930 requests and got 8929 responses
thread 3 made 8454 requests and got 8453 responses

stop.lua

running フェーズで stop 関数を使い、リクエスト数がしきい値を超えたら終了させる例。

補足

負荷試験中の名前解決について

The setup phase begins after the target IP address has been resolved and all threads have been initialized but not yet started.
https://github.com/wg/wrk/blob/master/SCRIPTING

とあるように running フェーズでは名前の再解決をしない。
負荷とともに IP が変わるようなケースでは注意をすること。

listen(2) backlog

To handle the initial connection burst the server’s listen(2) backlog should be greater than the number of concurrent connections being tested.
https://github.com/wg/wrk/blob/master/README

TODO

References

Leave a comment