Go製Bombardierで爆速負荷テスト

# Bombardierとは

[Bombardier](https://github.com/codesenberg/bombardier)とは、Go言語で書かれているHTTP(S)ベンチマークツール。Go言語の標準ライブラリである **net/http** ではなく、**fasthttp** を使用しているため超高速パフォーマンスで動く。(**net/http**クライアントも指定可能)
また、使い方もシンプルなため、**誰でも爆速で** ベンチマークを計測できる。

以下は、実際にBombardierを使って、Golangのフレームワークを比較してみた記事です。

https://qiita.com/twrcd1227/items/d871480ec9f8a581099e

# インストール

```
go install github.com/codesenberg/bombardier@latest
```

## bombardierの使い方

```
bombardier [オプション] <url>
```

コマンド例

```bash
bombardier -c [コネクション数] -n [リクエスト総数] -d [テスト実行時間] -t [タイムアウト] -o [出力形式] -H [header] <url>
```

オプションは以下のようになっている。


| オプション               | 説明                                                    |
|--------------------------|---------------------------------------------------------|
| --help                 | コマンドの説明表示                          |
| --version              | バージョンの表示                        |
| -c, --connections=125  | 同時に実行される最大の接続数を指定                        |
| -t, --timeout=2s       | ソケット/リクエストのタイムアウトを指定                  |
| -l, --latencies        | レイテンシ統計情報を表示                                |
| -m, --method=GET       | リクエストメソッドを指定                                |
| -b, --body=""          | リクエストのボディを指定                                |
| -f, --body-file=""     | ファイルをリクエストボディとして使用                      |
| --cert=""              | クライアントのTLS証明書のパス                            |
| --key=""               | クライアントのTLS証明書のプライベートキーのパス          |
| -k, --insecure         | サーバーの証明書チェーンとホスト名の検証を無効にする     |
| -H, --header="xxx: xxx"    | 使用するHTTPヘッダーを指定（複数回指定可能）              |
| -n, --requests         | リクエストの総数を指定                                  |
| -d, --duration=10s     | テストの実行時間を指定                                  |
| -r, --rate             | 秒間のリクエスト数の制限を指定                           |
| --fasthttp             | fasthttpクライアントを使用                              |
| --http1                | net/httpクライアントを強制的にHTTP/1.xで使用             |
| --http2                | net/httpクライアントを有効にしてHTTP/2.0を使用           |
| -p, --print            | 出力内容を指定。設定値はintro(i), progress(p), result(r)   |
| -q, --no-print         | 何も出力しない                                          |
| -o, --format           | 結果の出力形式を指定（plain-text, jsonなど）             |


# 測定してみる

## 測定対象サーバーの起動

ここではGinを使ってサーバーを実装する。

```go:main.go
package main

import "github.com/gin-gonic/gin"

func main() {
	gin.SetMode(gin.ReleaseMode)
	r := gin.New()
	r.GET("/", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "hello",
		})
	})
	r.Run()
}
```

```shell-session:terminal
go build
./main
```

## 測定

**bombardier** で測定する。

```shell-session:terminal
$ # コネクション数200で1000000リクエスト
$ bombardier -c 100 -n 1000000 http://localhost:8080
Bombarding http://localhost:8080 with 1000000 request(s) using 100 connection(s)
 1000000 / 1000000 [=====================================================================] 100.00% 199640/s 5s
Done!
Statistics        Avg      Stdev        Max
  Reqs/sec    203679.19   39224.54  263358.44
  Latency      490.20us   414.29us    18.17ms
  HTTP codes:
    1xx - 0, 2xx - 1000000, 3xx - 0, 4xx - 0, 5xx - 0
    others - 0
  Throughput:    39.59MB/s
$ # コネクション数200で1000000リクエスト
$ bombardier -c 200 -n 1000000 http://localhost:8080
Bombarding http://localhost:8080 with 1000000 request(s) using 200 connection(s)
 1000000 / 1000000 [=====================================================================] 100.00% 216890/s 4s
Done!
Statistics        Avg      Stdev        Max
  Reqs/sec    218654.05   36350.44  270508.77
  Latency        0.91ms   588.90us    37.51ms
  HTTP codes:
    1xx - 0, 2xx - 1000000, 3xx - 0, 4xx - 0, 5xx - 0
    others - 0
  Throughput:    42.58MB/s
```


200コネクションで10秒間リクエストする。

```shell-session:terminal
$ bombardier -c 200 -d 10s -l http://localhost:8080
Bombarding http://localhost:8080 for 10s using 200 connection(s)
[========================================================================================================] 10s
Done!
Statistics        Avg      Stdev        Max
  Reqs/sec    189932.72   64079.63  277627.63
  Latency        1.05ms     1.04ms    52.62ms
  Latency Distribution
     50%   690.00us
     75%     1.18ms
     90%     2.14ms
     95%     3.33ms
     99%     7.03ms
  HTTP codes:
    1xx - 0, 2xx - 1896791, 3xx - 0, 4xx - 0, 5xx - 0
    others - 0
  Throughput:    36.90MB/s
```

1コネクションで3秒間リクエストして**json**形式で出力する

```shell-session:terminal
$ bombardier -c 1 -d 3s -l http://localhost:8080 -o json
Bombarding http://localhost:8080 for 3s using 1 connection(s)
[=========================================================================================================] 3s
Done!
{"spec":{"numberOfConnections":1,"testType":"timed","testDurationSeconds":3,"method":"GET","url":"http://localhost:8080","body":"","stream":false,"timeoutSeconds":2,"client":"fasthttp"},"result":{"bytesRead":6789304,"bytesWritten":2964344,"timeTakenSeconds":2.999872085,"req1xx":0,"req2xx":47812,"req3xx":0,"req4xx":0,"req5xx":0,"others":0,"latency":{"mean":61.435873839203545,"stddev":77.60540802060129,"max":8013,"percentiles":{"50":59,"75":65,"90":72,"95":78,"99":116}},"rps":{"mean":15947.522413460345,"stddev":2266.500536802793,"max":22738.914779045215,"percentiles":{"50":16218.549967,"75":16527.417368,"90":17016.236042,"95":18311.632725,"99":20557.168448}}}}
```