自社サイトがベジータの攻撃に耐えられるかテストしよう！

# はじめに
Vegetaという負荷テストツールが手軽に使えて便利だったので、
紹介＋備忘として、使い方を簡単に残します。
https://github.com/tsenart/vegeta

# Vegetaの概要と特徴
Vegetaは、Go言語で実装された高性能なHTTP負荷テストツールです。WebサービスやAPIの性能評価や耐久性テストに使用されます。
Vegetaの名前は、ご存知「ドラ○ンボール」のあの人から取られています。
サイトを攻撃して負荷をかけるツールにピッタリの名称ですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3294382/96a9067f-3936-aaa4-5a24-e05d8c389549.png)
※ 画像はイメージです


# インストール
Macの場合、brewでインストールできます。
その他の環境については、[GitHub](https://github.com/tsenart/vegeta) を参照してください。
```
brew update && brew install vegeta
```

# 基本的な使い方
サンプルでは `localhost` 宛としています。
宛先は適宜変更してください。

:::note warn
くれぐれも想定外のサイトに負荷をかけないようご注意ください。
:::

## vegeta attack コマンドで負荷をかける

`http://localhost:8080/` に `100rps` で `10分間` 負荷をかける場合は、以下のように書きます。
```
echo "GET http://localhost:8080/" | vegeta attack -rate=100/s -duration=10m
```

### よく使うオプション

| オプション       | 説明                                                         |
|----------------|------------------------------------------------------------|
| -rate          | リクエストのレート（秒あたりのリクエスト数）を指定します。省略した場合は無制限。                        |
| -duration      | 負荷テストの実行時間を指定します。                                      |
| -body          | リクエストボディを指定します。                                             |
| -format          | リクエスト指定方法のフォーマットを指定します。 `json` or `http` (デフォルト)                                             |

### -format=http 形式での指定

テキスト形式でターゲットを指定します。
```
# メソッドとリクエスト先だけ指定
GET http://localhost:8080/path/to/dragon?item=ball

# ヘッダを指定
DELETE http://localhost:8080/path/to/remove
Confirmation-Token: 90215
Authorization: Token DEADBEEF

# 外部のボディを指定
POST http://localhost:8080/things
@/path/to/newthing.json
```

上記を `target.txt` で保存した場合、以下のようなコマンドで負荷をかけることができます。

```
cat target.txt | vegeta attack -rate=100/s -duration=10m
```

### -format=json 形式での指定
[JSON Schema](https://github.com/tsenart/vegeta/blob/master/lib/target.schema.json) を参考に、JSON形式でターゲットを指定します。  
この形式の場合、bodyはbase64形式に変換して指定する必要があります。
```
jq -ncM '{method: "GET", url: "http://goku", body: "Punch!" | @base64, header: {"Content-Type": ["text/plain"]}}' |
  vegeta attack -format=json -rate=100 | vegeta encode
```

## vegeta rport で結果レポートを出力する

`vegeta attack` の結果を `vegeta report` に渡すことで結果レポートを確認することができます。  
結果の見方の詳細はここでは割愛します。

```
echo "GET http://localhost:8080/" | \
    vegeta attack -rate=1/s -duration=5s | \
    tee results.bin | \
    vegeta report

# 後から結果を確認する場合
cat results.bin | vegeta report
```

結果は以下のように出力されます。
```
Requests      [total, rate, throughput]         5, 1.25, 1.25
Duration      [total, attack, wait]             4s, 4s, 529.75µs
Latencies     [min, mean, 50, 90, 95, 99, max]  529.75µs, 1.318ms, 974.959µs, 3.137ms, 3.137ms, 3.137ms, 3.137ms
Bytes In      [total, mean]                     145, 29.00
Bytes Out     [total, mean]                     0, 0.00
Success       [ratio]                           100.00%
Status Codes  [code:count]                      200:5  
Error Set:
```

エラーが発生した場合は、以下のように出力される。
```
Requests      [total, rate, throughput]         5, 1.25, 1.00
Duration      [total, attack, wait]             4.001s, 4s, 902.458µs
Latencies     [min, mean, 50, 90, 95, 99, max]  505.25µs, 1.167ms, 815.75µs, 2.857ms, 2.857ms, 2.857ms, 2.857ms
Bytes In      [total, mean]                     136, 27.20
Bytes Out     [total, mean]                     0, 0.00
Success       [ratio]                           80.00%
Status Codes  [code:count]                      200:4  503:1  
Error Set:
503 Service Unavailable
```

### -type=json で JSON形式で出力
#### コマンド例
```
cat results.bin | vegeta report -type=json
```

#### 結果

```
{"latencies":{"total":6635081,"mean":1327016,"50th":503416,"90th":4598583,"95th":4598583,"99th":4598583,"max":4598583,"min":362208},"bytes_in":{"total":136,"mean":27.2},"bytes_out":{"total":0,"mean":0},"earliest":"2024-06-17T23:09:21.047830584+09:00","latest":"2024-06-17T23:09:25.047845709+09:00","end":"2024-06-17T23:09:25.048349125+09:00","duration":4000015125,"wait":503416,"requests":5,"rate":1.2499952734553723,"throughput":0.9998703815531198,"success":0.8,"status_codes":{"200":4,"503":1},"errors":["503 Service Unavailable"]}
```


### -type=`hist[buckets]` で ヒストグラム形式で出力
#### コマンド例
```
cat results.bin | vegeta report -type='hist[0,2ms,4ms,6ms]'
```

#### 結果

```
Bucket         #  %       Histogram
[0s,    2ms]   4  80.00%  ############################################################
[2ms,   4ms]   0  0.00%   
[4ms,   6ms]   1  20.00%  ###############
[6ms,   +Inf]  0  0.00%  
```

### -type=hdrplot で ヒストグラム形式で出力
[HdrHistogram Plotter](https://hdrhistogram.github.io/HdrHistogram/plotFiles.html) で読み込み可能な形式のプロットを出力できます。

#### コマンド例
```
cat results.bin | vegeta report -type=hdrplot
```

#### 結果

```
Value(ms)  Percentile  TotalCount  1/(1-Percentile)
0.529667   0.000000    0           1.000000
0.529667   0.100000    1           1.111111
0.697541   0.200000    1           1.250000
0.865416   0.300000    2           1.428571

〜中略〜

4.421084   0.999996    5           250000.000000
4.421084   0.999997    5           333333.333336
4.421084   0.999998    5           500000.000013
4.421084   0.999999    5           999999.999971
4.421084   1.000000    5           10000000.000000
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3294382/91bda4a7-46b0-b778-3aed-528a221b750d.png)

## vegeta plot で HTML出力

`vegeta plot` で 負荷テストの結果グラフをHTML出力することができます。

```
echo "GET http://localhost:8080/" | \    
    vegeta attack -rate=50/s -duration=1m | \
    tee results.bin | \
    vegeta plot > plot.html
```

![vegeta-plot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3294382/093943b2-64d9-a3cc-3e17-eee44bd11e6a.png)


# 最後に
負荷テストツール `vegeta` の基本的な使い方について説明しました。  
基本的な部分のみ紹介しましたが、動的なリクエスト生成や分散リクエスト、別のツールと連携したリアルタイムのグラフ生成など、他にも色々と出来ることがあります。  
機会があれば応用編も執筆したいと思います。