モダンな 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