HTTPベンチマークツール wrk2の使い方メモとLuaスクリプトのサンプル

## wrk2って何？
```wrk```というhttp通信における応答時間を計測することができるベンチマークツールがある。


https://github.com/wg/wrk

```wrk2```はその改良版で、出力の内容や測定方法に若干の変更が加えられている。

https://github.com/giltene/wrk2

基本的な使い方などは```wrk```を踏襲しているので、困ったことがあるなら```wrk```のドキュメントを読んだ方が早かったりする。
今回これを用いたベンチマークテストの手順をまとめておく。

## 導入方法
ubuntuに対して導入する。

```wkr2```の導入を行うマシンで、以下を実行する。

#### 1. 必要なツールをいろいろ入れる

```
sudo apt install build-essential
sudo apt install libssl-dev
sudo apt install zlib1g-dev
```
#### 2. ソースコードを取得する
```
git clone https://github.com/giltene/wrk2.git
```

#### 3. ビルドする
先ほどのwrk2のディレクトリに移動して、以下を実行する。
```
make
```
導入できていることを確認する。
```
wrk --version
```

以上で導入は完了。

なお、```yum```での導入は以下を参考にできる。

https://siguniang.wordpress.com/2015/06/21/notes-on-wrk-http-benchmarking-tool/

## 実行してみる

以下は[公式](https://github.com/giltene/wrk2)の実行サンプル。
```
wrk -t2 -c100 -d30s -R2000 --latency http://127.0.0.1:80/index.html
```

ここで
* ```t```で指定した数はスレッド数
* ```c```で指定した数はhttp connectionの数
* ```d```で指定した数は実行する時間(これは30秒)
* ```R```で指定した数は秒間あたりのリクエスト数(全スレッド、全接続の合計数)

を表す。
この場合```-R2000```、```-d30s```と指定すれば、(応答時間が十分に早いとすれば)合計$2000\times30=60000$個のリクエストを送ることになる。

これで以下のような出力([公式サンプル](https://github.com/giltene/wrk2))が得られる。
こうして応答時間をパーセンタイル値として見ることができる。
```
Running 30s test @ http://127.0.0.1:80/index.html
  2 threads and 100 connections
  Thread calibration: mean lat.: 10087 usec, rate sampling interval: 22 msec
  Thread calibration: mean lat.: 10139 usec, rate sampling interval: 21 msec
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     6.60ms    1.92ms  12.50ms   68.46%
    Req/Sec     1.04k     1.08k    2.50k    72.79%
  Latency Distribution (HdrHistogram - Recorded Latency)
 50.000%    6.67ms
 75.000%    7.78ms
 90.000%    9.14ms
 99.000%   11.18ms
 99.900%   12.30ms
 99.990%   12.45ms
 99.999%   12.50ms
100.000%   12.50ms

Detailed Percentile spectrum:
     Value   Percentile   TotalCount 1/(1-Percentile)
     
     0.921     0.000000            1         1.00 
     4.053     0.100000         3951         1.11
     4.935     0.200000         7921         1.25
     5.627     0.300000        11858         1.43
(以下省略)
```

## Luaスクリプトで設定してみよう

送信する各種パラメータの設定やレスポンスを用いた処理などしたい場合、Luaスクリプトを作成する必要がある。

Luaわからんけどこれを書きたい場合はscripts/の中にサンプルとなるLuaスクリプトがいくつか用意されているので、これらを見ながら作成するといい。

### POSTの設定
```wrk.method```の設定、```wrk.headers["Content-Type"]```の設定、```wrk.body```の設定を行う。ついでに```string.format```も使うのでサンプルとして入れた。
```lua:sample.lua
wrk.method = "POST"
wrk.headers["Content-Type"] = "application/json"

params = "{\"hoge\": \"1\"}"
wrk.body = string.format("{\"fuga\": \"1\", \"params\": %s}", params);
```

```x-www-form-urlencoded```ではこういう感じ。(公式サンプル)
```lua:post.lua
wrk.body   = "foo=bar&baz=quux"
wrk.headers["Content-Type"] = "application/x-www-form-urlencoded"
```

### request関数とresponse関数の使い方
```scripts/setup.lua```などを見ればわかるように、```init``` ```request``` ```response``` ```done```といった特定のタイミングで動く関数が用意されている。特にこの中でも```request``` ```response```の二つについて使い方を見てみる。

#### request

```request```を行うときに動く関数。引数は持たない。

requestを送信するたびに新しい```uuid```を発行して送信するようなスクリプトを作ってみる。

```uuid```の生成方法は以下のものを使わせていただいた。

https://gist.github.com/jrus/3197011

```lua: request.lua
math.randomseed(os.time())
local random = math.random

local function uuid()
    local template ='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
    return string.gsub(template, '[xy]', function (c)
        local v = (c == 'x') and random(0, 0xf) or random(8, 0xb)
        return string.format('%x', v)
    end)
end

wrk.method = "POST"
wrk.headers["Content-Type"] = "application/json"

function request()
        body = string.format("{\"id\": \"%s\"}", uuid());
        return wrk.format(nil, nil, nil, body)
end
```

ここで```wrk.format(method, path, headers, body)```はそれぞれ指定した値をパラメータとして設定するためのメソッド。今回はbodyだけを指定したいので、その他をnilとした。

#### response

```response```を受け取るときに動く関数。引数はstatus, headers, bodyの三つを持つ。

responseを受け取った時に処理を中断し、その結果をファイルに出力することで動作のチェックを行う。以下の記事を参考にさせていただいた。

https://uzulla.hateblo.jp/entry/2015/11/11/185701

```lua: response.lua
function response(status, headers, body)
  log = io.open("wrk.log", "w");
  log:write("status:" .. status .. "\n" .. body);
  wrk.thread:stop()
end
```

### スクリプトを含めて実行する

これらのスクリプトを含めて実行する場合は、以下のようにコマンドに```-s```を加えて実行する。

```
wrk -t2 -c100 -d30s -R2000 --latency -s scripts/test.lua http://127.0.0.1:80/index.html
```