DEV Community

Cover image for ベジータ負荷テスト:定速HTTPチュートリアル
Akira
Akira

Posted on • Originally published at apidog.com

ベジータ負荷テスト:定速HTTPチュートリアル

APIが「1秒あたり500リクエスト」でどう振る舞うかを知りたいのであって、「Nスレッドでどれだけ速く叩けるか」を知りたいわけではありません。多くの負荷テストツールは同時実行数を固定し、実際のリクエストレートはサーバーの応答速度に左右されます。一方、Vegetaはリクエストレートを固定します。指定したRPSを、サーバーの応答に関係なく送信し続けます。この違いは、目標負荷でのスループット、SLOで約束するレイテンシ、容量限界を正しく測るうえで重要です。

今すぐApidogを試す

Vegetaとは

Vegetaは、Goで書かれたCLIベースのHTTP負荷テストツールです。Goライブラリとしても使えますが、この記事ではCLIでの使い方に絞ります。

Vegetaの中心的な特徴は、一定のリクエストレートです。

たとえば「30秒間、1秒あたり100リクエストを送る」と指定すると、Vegetaはそのペースを維持するために必要なワーカーを使ってリクエストを送信します。サーバーが遅くなっても、前のリクエストの完了を待たず、スケジュールどおりに次のリクエストを発行します。

これはオープンモデルの負荷テストです。実際の本番トラフィックでも、次のユーザーは前のユーザーの遅いレスポンスを待ってくれません。レートベースの負荷テストは、その到着パターンに近い形でAPIを測定できます。

レートベースの負荷 vs 同時実行数ベースの負荷

負荷テストでは、まず「何を固定するのか」を決める必要があります。

同時実行数ベース

同時実行数ベースのツールでは、固定されたスレッド、仮想ユーザー、またはワーカーがリクエストとレスポンスをループします。これはクローズドモデルです。

サーバーが遅くなると、各ワーカーはレスポンス待ちで止まります。その結果、実際に送られるリクエストレートが下がります。つまり、負荷をかけているつもりでも、ツール側が自然に送信を控えてしまう場合があります。

この挙動は、本番で発生するボトルネックを隠すことがあります。

レートベース

Vegetaのようなレートベースのツールでは、到着レートを固定します。サーバーが追いつけない場合、リクエストは滞留し、レイテンシが上がり、エラーが発生する可能性があります。

そのため、次のような問いに向いています。

  • 500 RPSでp95レイテンシはどれくらいか
  • 1,000 RPSを超えたときに5xxが出るか
  • どのレートからテールレイテンシが悪化するか
  • 同じRPSで新旧ビルドを比較するとどちらが速いか

どちらのモデルも間違いではありません。

「同時に何人のユーザーを維持できるか」を見たいなら同時実行数ベース、「1秒あたり2,000リクエストで何が起こるか」を見たいならレートベースを使います。

ツール全体の比較については、主要なAPI負荷テストツールも参考になります。

Vegetaのインストール

環境に合わせてインストールします。

macOSでHomebrewを使う場合:

brew update && brew install vegeta
Enter fullscreen mode Exit fullscreen mode

その他のパッケージマネージャー:

# MacPorts
port install vegeta

# Arch Linux
pacman -S vegeta

# FreeBSD
pkg install vegeta
Enter fullscreen mode Exit fullscreen mode

Goがインストールされている場合は、ソースからビルドできます。

git clone https://github.com/tsenart/vegeta
cd vegeta
make vegeta
Enter fullscreen mode Exit fullscreen mode

GitHubのリリースページからビルド済みバイナリをダウンロードすることもできます。

インストール確認:

vegeta --help
Enter fullscreen mode Exit fullscreen mode

基本パイプライン

VegetaはUnixパイプで扱いやすい設計です。

基本形は次のとおりです。

echo "GET http://localhost:8080/" | vegeta attack -duration=5s -rate=100 | vegeta report
Enter fullscreen mode Exit fullscreen mode

このコマンドは以下を実行します。

  1. echoでターゲットを1件出力する
  2. vegeta attackが5秒間、100 RPSでリクエストを送る
  3. vegeta reportが結果を集計して表示する

この例では合計約500リクエストを送ります。

-rateには時間単位あたりのリクエスト数を指定します。

-rate=100      # 1秒あたり100リクエスト
-rate=100/1s   # 同じ意味
-rate=50/500ms # 500ミリ秒あたり50リクエスト
Enter fullscreen mode Exit fullscreen mode

-rate=0を指定するとレート制限が解除され、可能な限り高速に送信されます。これは一定レートの容量測定とは別のテストになるため、再現性を重視する場合は明示的なレートを指定してください。

レポートの読み方

テキストレポートは次のような形式です。

Requests      [total, rate, throughput]  500, 100.20, 100.18
Duration      [total, attack, wait]      4.991s, 4.990s, 1.2ms
Latencies     [min, mean, 50, 90, 95, 99, max]  412us, 1.3ms, 1.1ms, 1.9ms, 2.4ms, 5.1ms, 12ms
Bytes In      [total, mean]              128500, 257.00
Bytes Out     [total, mean]              0, 0.00
Success       [ratio]                    100.00%
Status Codes  [code:count]               200:500
Error Set:
Enter fullscreen mode Exit fullscreen mode

まず見るべき項目は以下です。

項目 見るポイント
Requests 総リクエスト数、実際の送信レート、スループット
Latencies p50、p90、p95、p99、最大値
Success 成功率
Status Codes 2xx、4xx、5xxの内訳
Error Set タイムアウトや接続エラーなど

特に重要なのはp95とp99です。平均値が良くても、p99が悪ければ一部のユーザーは遅いレスポンスを体験しています。

結果を保存して再利用する

一度きりの確認なら、attackからreportへ直接パイプして問題ありません。

ただし、比較やCIで使う場合は、生の結果をファイルに保存してからレポートを生成します。

echo "GET http://localhost:8080/" | \
  vegeta attack -duration=10s -rate=200 -output=results.bin
Enter fullscreen mode Exit fullscreen mode

テキストレポートを生成:

vegeta report results.bin
Enter fullscreen mode Exit fullscreen mode

JSONで出力:

vegeta report -type=json results.bin > metrics.json
Enter fullscreen mode Exit fullscreen mode

ヒストグラムを出力:

vegeta report -type='hist[0,2ms,5ms,10ms,25ms,100ms]' results.bin
Enter fullscreen mode Exit fullscreen mode

ヒストグラムを使うと、レイテンシがどの範囲に集中しているかを確認できます。p95やp99だけでなく、分布全体を把握したいときに便利です。

ターゲットファイルを使う

実際のAPIでは、1つのGETだけでなく、複数のエンドポイントやPOSTボディを含むリクエストを扱います。

その場合はターゲットファイルを作ります。

targets.txt:

GET http://localhost:8080/api/users

POST http://localhost:8080/api/users
Content-Type: application/json
@./payload.json

GET http://localhost:8080/api/users/42
Enter fullscreen mode Exit fullscreen mode

ルールは以下です。

  • 各ターゲットの最初の行はMETHOD URL
  • ヘッダーはメソッド行の直下に書く
  • ヘッダーは1行に1つのKey: Value
  • @で始まる行はリクエストボディ用ファイルを指定する
  • 空行でターゲットを区切る
  • #で始まる行はコメント

POSTボディを用意します。

payload.json:

{ "name": "Ada", "role": "engineer" }
Enter fullscreen mode Exit fullscreen mode

実行:

vegeta attack -targets=targets.txt -rate=50 -duration=30s | vegeta report
Enter fullscreen mode Exit fullscreen mode

Vegetaはターゲットを順番に巡回し、指定した時間が終わるまで繰り返します。

認証ヘッダーのように全リクエストへ共通で付けたいヘッダーは、-headerで指定できます。

vegeta attack -targets=targets.txt -rate=50 -duration=30s \
  -header="Authorization: Bearer $TOKEN" | vegeta report
Enter fullscreen mode Exit fullscreen mode

JSONターゲット形式を使う

プログラムでターゲットを生成する場合や、大量のリクエスト定義を扱う場合はJSON形式が便利です。

各行に1つのJSONオブジェクトを書き、-format=jsonを指定します。

{"method": "GET", "url": "http://localhost:8080/api/users"}
{"method": "POST", "url": "http://localhost:8080/api/users", "header": {"Content-Type": ["application/json"]}, "body": "eyJuYW1lIjoiQWRhIn0="}
Enter fullscreen mode Exit fullscreen mode

bodyはbase64エンコードされた値です。

実行例:

vegeta attack -format=json -targets=targets.json -rate=100 -duration=30s | vegeta report
Enter fullscreen mode Exit fullscreen mode

ターゲットを標準出力で生成してパイプする場合は、-lazyを使うとメモリ効率よく処理できます。

generate-targets | vegeta attack -format=json -lazy -rate=100 -duration=30s | vegeta report
Enter fullscreen mode Exit fullscreen mode

プロットでレイテンシ推移を見る

単一の数値だけでは、テスト中盤での悪化やスパイクを見落とすことがあります。

Vegetaのplotを使うと、結果をHTMLで可視化できます。

vegeta attack -targets=targets.txt -rate=100 -duration=60s | \
  vegeta plot > plot.html
Enter fullscreen mode Exit fullscreen mode

ブラウザでplot.htmlを開くと、レイテンシの時系列を確認できます。

複数の負荷レベルを比較する場合:

vegeta attack -rate=50  -duration=30s -targets=targets.txt -output=50qps.bin
vegeta attack -rate=100 -duration=30s -targets=targets.txt -output=100qps.bin
vegeta plot 50qps.bin 100qps.bin > compare.html
Enter fullscreen mode Exit fullscreen mode

ヘッドレス環境やCIでは、CSVに変換して保存する方法もあります。

vegeta encode -to=csv results.bin > results.csv
Enter fullscreen mode Exit fullscreen mode

Vegetaを使うべきケース

Vegetaは、レートと容量に関する検証に向いています。

使うべきケース:

  • 特定RPSでのスループットとレイテンシを測りたい
  • エラー率やテールレイテンシが悪化し始めるレートを見つけたい
  • 同じ負荷条件で2つのビルドを比較したい
  • インフラ構成変更の前後で性能差を見たい
  • GUIなしでCIやシェルスクリプトに組み込みたい

一方で、Vegetaは複雑なユーザーシナリオの分岐や、レスポンスボディの詳細な検証には向いていません。一定レートでHTTPリクエストを送り、レスポンス時間、ステータスコード、エラーを測ることに特化したツールです。

他の負荷テストツールも比較したい場合は、k6負荷テストJMeter負荷テストも参考になります。

基本概念やメトリクスを整理したい場合は、APIパフォーマンステストチュートリアルを確認してください。

機能テストと負荷テストを分ける

負荷テストは「十分に速いか」を確認します。

しかし、「正しいレスポンスを返しているか」は確認しません。

たとえばVegetaの結果が100%成功で、すべて200番台だったとしても、APIが次のような誤った値を返している可能性はあります。

  • 別ユーザーのデータ
  • 古い価格
  • 必須フィールドが欠けたJSON
  • ビジネスルールに違反したレスポンス

Vegetaにとっては、これらも「高速に返った200レスポンス」です。

正しさを確認するには、レスポンスボディ、スキーマ、ヘッダー、ビジネスルールに対するアサーションが必要です。これは機能テストの役割です。

実運用では、次の順番にすると安全です。

  1. 機能テストでAPIの正しさを確認する
  2. 合格したエンドポイントに対してVegetaで負荷をかける
  3. レイテンシ、スループット、エラー率を評価する

ApidogとVegetaを組み合わせる

ApidogはVegetaの代替ではなく、補完として使えます。

Apidogでは、ステータスコード、ヘッダー、JSONフィールドなどに対するアサーションを含むテストシナリオを作成できます。複数リクエストを連結し、データファイルで駆動することもできます。

使い分けは次のとおりです。

ツール 役割
Apidog APIが正しいレスポンスを返すか確認する
Vegeta 正しいAPIが指定RPSで高速に動くか測る

Apidog CLIを使うと、機能テストをCIで実行できます。

インストール:

npm install -g apidog-cli
Enter fullscreen mode Exit fullscreen mode

保存済みのシナリオまたはスイートを実行:

apidog run --access-token "$APIDOG_ACCESS_TOKEN" \
  -t <scenarioOrSuiteId> \
  -e <environmentId> \
  -r cli,html,junit
Enter fullscreen mode Exit fullscreen mode

主なオプション:

  • -t: シナリオ、フォルダー、またはスイートID
  • -e: 環境ID
  • -r: レポーター。clihtmljsonjunitなど

junit出力は多くのCIダッシュボードに取り込めます。

詳しい手順は、Apidog CLIコマンドラインチュートリアルCI/CDパイプラインガイドを参照してください。

CIでは、たとえば次の順番で実行します。

# 1. 機能テスト
apidog run --access-token "$APIDOG_ACCESS_TOKEN" \
  -t <scenarioOrSuiteId> \
  -e <environmentId> \
  -r cli,junit

# 2. 負荷テスト
vegeta attack -targets=targets.txt -rate=100 -duration=60s -output=results.bin

# 3. レポート生成
vegeta report results.bin
vegeta report -type=json results.bin > metrics.json
Enter fullscreen mode Exit fullscreen mode

よくある質問

Vegetaはボディ付きPOSTリクエストをサポートしていますか?

はい。HTTPターゲットファイルでは、メソッドとURLを書いたあとにContent-Typeヘッダーを追加し、@./payload.jsonでボディファイルを参照します。

POST http://localhost:8080/api/users
Content-Type: application/json
@./payload.json
Enter fullscreen mode Exit fullscreen mode

JSONターゲット形式では、methodurl、base64エンコード済みのbodyを指定します。

-rate=0は何をしますか?

レート制限を解除し、ワーカーと接続が許す限り高速にリクエストを送信します。

これは最大スループットテストであり、一定レートでの再現性ある容量測定とは別物です。SLOや特定RPSでの挙動を測る場合は、明示的に-rateを指定してください。

レイテンシのパーセンタイルはどう読めばよいですか?

Latencies行には、最小値、平均値、p50、p90、p95、p99、最大値が表示されます。

特にp95とp99を確認してください。平均値では見えない、一部ユーザーが体験する遅いレスポンスを把握できます。

VegetaはAPIが正しいデータを返すか確認できますか?

いいえ。Vegetaはスループット、レイテンシ、ステータスコード、エラーを測定します。レスポンスボディやスキーマに対するアサーションは行いません。

正確性は機能テストツールで確認し、性能測定にVegetaを使う構成が適しています。

CIでVegetaを実行するにはどうすればよいですか?

Vegetaは標準入力とファイル出力に対応した単一バイナリなので、通常のシェルステップに組み込めます。

例:

vegeta attack -targets=targets.txt -rate=200 -duration=60s -output=results.bin
vegeta report results.bin
vegeta report -type=json results.bin > metrics.json
Enter fullscreen mode Exit fullscreen mode

負荷テストの前にApidog CLIなどで機能ゲートを実行し、アサーションに合格したAPIだけをVegetaで測定すると、より信頼できるパイプラインになります。

Top comments (0)