DEV Community

Cover image for ApacheBench (ab)を使ったターミナルでのAPI負荷テストのやり方
Akira
Akira

Posted on • Originally published at apidog.com

ApacheBench (ab)を使ったターミナルでのAPI負荷テストのやり方

あなたはエンドポイントをリリースしました。Postmanでは正しいJSONが返ります。しかし、200クライアントが同時にアクセスしたとき、毎秒500リクエストを処理できるのか、50リクエストでレイテンシが崩れるのかは分かりません。ApacheBenchなら、1コマンドで単一エンドポイントのスループットとレイテンシを確認できます。

今すぐApidogを試す

ab として呼び出されるApacheBenchは、指定したURLに固定数のHTTPリクエストを送り、スループットとレイテンシを出力するCLIツールです。Apache HTTP Serverに同梱されており、単一エンドポイントの負荷耐性を素早く確認する用途に向いています。

この記事では、ab のインストール、基本的なGETテスト、POSTエンドポイントのテスト、出力の読み方、そして ab を使うべきでないケースを実装手順ベースで説明します。ここで使うフラグは、公式の Apache abリファレンス に対応しています。

ApacheBenchとは何か

ab は、Apache HTTP Serverにバンドルされているベンチマーククライアントです。単一URLに対して接続を開き、指定した同時実行数でリクエストを送り、各レスポンス時間を計測します。

ApacheBench

ab が測定できるのは、主に次の2つです。

  • 単一エンドポイントが処理できる毎秒リクエスト数
  • 負荷がかかったときのレスポンス時間の分布

つまり、1つのURLに対するスループットとレイテンシを見るためのツールです。

一方で、ab はレスポンスボディの正しさを検証しません。JSONスキーマの検証、フィールド値のアサーション、ログインから更新までの多段階フローの実行もできません。1つのURLにリクエストを送り、結果を数えるだけです。

ab がAPI負荷テスト全体の中でどこに位置づけられるかを整理したい場合は、API負荷テストとは何かAPIレスポンス時間がなぜ重要か も参考になります。

abのインストール

ab はApache関連ユーティリティとして配布されています。パッケージ名はOSによって異なります。

Debian / Ubuntu

sudo apt-get update
sudo apt-get install -y apache2-utils
Enter fullscreen mode Exit fullscreen mode

CentOS / RHEL / Fedora

# CentOS 7
sudo yum install -y httpd-tools

# Fedora and CentOS 8+
sudo dnf install -y httpd-tools
Enter fullscreen mode Exit fullscreen mode

macOS

macOSでは、多くの場合 ab がすでに利用できます。

ab -V
Enter fullscreen mode Exit fullscreen mode

Version 2.3 のようなバージョン情報が表示されれば準備完了です。

コマンドが見つからない場合は、Homebrew経由でApacheをインストールし、再度確認してください。

brew install httpd
ab -V
Enter fullscreen mode Exit fullscreen mode

基本的な負荷テストを実行する

ab で最初に覚えるフラグは -n-c です。

  • -n requests: 実行するリクエスト総数
  • -c concurrency: 同時に実行するリクエスト数

例えば、JSONエンドポイントに対して1000リクエストを50並列で送る場合は次のように実行します。

ab -n 1000 -c 50 https://api.example.com/v1/users
Enter fullscreen mode Exit fullscreen mode

ab にはパスを含む完全なURLが必要です。ルートをテストする場合も、末尾の / を含めます。

ab -n 1000 -c 50 https://api.example.com/
Enter fullscreen mode Exit fullscreen mode

KeepAliveを有効にする

実際のブラウザやAPIクライアントは、通常リクエストごとにTCP接続を作り直しません。接続再利用に近い条件で測るには -k を追加します。

ab -n 1000 -c 50 -k https://api.example.com/v1/users
Enter fullscreen mode Exit fullscreen mode

-k を付けた結果と付けない結果を比較すると、接続確立コストがレイテンシにどれくらい影響しているかを確認できます。

時間ベースで実行する

リクエスト数ではなく、実行時間で制限したい場合は -t を使います。

ab -t 30 -c 50 -k https://api.example.com/v1/users
Enter fullscreen mode Exit fullscreen mode

この例では、同時実行数50で最大30秒間テストします。固定時間で負荷をかけたいときに便利です。

POSTエンドポイントをテストする

POST APIをテストする場合は、リクエストボディをファイルに保存し、-p で指定します。JSON APIでは -T application/json も必ず指定します。

まず、ペイロードを作成します。

cat > payload.json <<'EOF'
{"name": "Ada Lovelace", "email": "ada@example.com"}
EOF
Enter fullscreen mode Exit fullscreen mode

次に、POSTリクエストを実行します。

ab -n 500 -c 25 -k \
  -p payload.json \
  -T application/json \
  https://api.example.com/v1/users
Enter fullscreen mode Exit fullscreen mode

各フラグの意味は次の通りです。

  • -p payload.json: POSTボディとして使うファイル
  • -T application/json: Content-Type ヘッダー
  • -n 500: 合計500リクエスト
  • -c 25: 25並列
  • -k: KeepAlive有効

認証が必要なAPIでは、-H でヘッダーを追加します。

ab -n 500 -c 25 -k \
  -p payload.json \
  -T application/json \
  -H "Authorization: Bearer YOUR_TOKEN" \
  https://api.example.com/v1/users
Enter fullscreen mode Exit fullscreen mode

複数のヘッダーが必要な場合は、-H を繰り返します。

ab -n 500 -c 25 -k \
  -p payload.json \
  -T application/json \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "X-Request-Source: ab-test" \
  https://api.example.com/v1/users
Enter fullscreen mode Exit fullscreen mode

JSONリクエストボディの作り方を確認したい場合は、curlでJSONデータをPOSTする方法 を参照してください。同じJSONを ab のペイロードファイルとして利用できます。

出力の読み方

ab を実行すると、次のような結果が出力されます。

Concurrency Level:      50
Time taken for tests:   4.212 seconds
Complete requests:      1000
Failed requests:        0
Non-2xx responses:      0
Requests per second:    237.42 [#/sec] (mean)
Time per request:       210.598 [ms] (mean)
Time per request:       4.212 [ms] (mean, across all concurrent requests)
Transfer rate:          142.31 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        5   18   9.4     16      64
Processing:    22  189  41.2    182     310
Waiting:       21  177  39.8    171     295
Total:         31  207  42.7    201     338

Percentage of the requests served within a certain time (ms)
  50%    201
  66%    221
  75%    236
  90%    268
  95%    291
  99%    324
 100%    338 (longest request)
Enter fullscreen mode Exit fullscreen mode

まず確認すべき項目は次の4つです。

Requests per second

Requests per second:    237.42 [#/sec] (mean)
Enter fullscreen mode Exit fullscreen mode

スループットの主要指標です。数値が高いほど、同じ時間で多くのリクエストを処理できています。

ただし、この数値だけで判断してはいけません。エラーが大量に出ている状態でも、表面上のRPSは高く見えることがあります。

Failed requests / Non-2xx responses

Failed requests:        0
Non-2xx responses:      0
Enter fullscreen mode Exit fullscreen mode

負荷をかけた結果、サーバーが正常に応答できたかを確認します。

特に次のような状態では、RPSが高くても有効な結果とは言えません。

  • Failed requests が多い
  • Non-2xx responses が増えている
  • 500系エラーが発生している
  • タイムアウトが増えている

Time per request

Time per request:       210.598 [ms] (mean)
Time per request:       4.212 [ms] (mean, across all concurrent requests)
Enter fullscreen mode Exit fullscreen mode

Time per request は2行あります。

1行目は、ユーザー視点の平均待ち時間に近い値です。

2行目は、全同時実行リクエストをまたいだ平均処理間隔です。

API利用者が体感するレイテンシを見るなら、主に1行目を見ます。

パーセンタイル

Percentage of the requests served within a certain time (ms)
  50%    201
  95%    291
  99%    324
Enter fullscreen mode Exit fullscreen mode

この表が実運用では重要です。

  • 50%: 中央値
  • 95%: 95パーセンタイル
  • 99%: 99パーセンタイル

平均値だけでは、遅いリクエストの影響が見えにくくなります。実際のユーザー体験を考えるなら、95パーセンタイルと99パーセンタイルを必ず確認してください。

この例では、半分のリクエストは201ms以内に完了していますが、1%は324ms以上かかっています。

結果をCSVやTSVで保存する

チャート化したい場合は、-e または -g を使います。

CSVで保存する

ab -n 1000 -c 50 -k \
  -e results.csv \
  https://api.example.com/v1/users
Enter fullscreen mode Exit fullscreen mode

-e results.csv は、パーセンタイルと時間のペアをCSVとして出力します。

gnuplot向けTSVで保存する

ab -n 1000 -c 50 -k \
  -g results.tsv \
  https://api.example.com/v1/users
Enter fullscreen mode Exit fullscreen mode

-g results.tsv は、gnuplotで扱いやすい形式のファイルを生成します。

実践的なテスト手順

単発で大きな負荷をかけるより、段階的に同時実行数を上げる方が原因を追いやすくなります。

例えば、次のように実行します。

ab -n 1000 -c 10 -k https://api.example.com/v1/users
ab -n 1000 -c 25 -k https://api.example.com/v1/users
ab -n 1000 -c 50 -k https://api.example.com/v1/users
ab -n 1000 -c 100 -k https://api.example.com/v1/users
Enter fullscreen mode Exit fullscreen mode

各実行で見るべきポイントは次の通りです。

  • RPSがどこまで伸びるか
  • どの同時実行数でRPSの伸びが止まるか
  • 95p / 99pレイテンシが急に悪化する点はどこか
  • Failed requestsNon-2xx responses が増え始める点はどこか

RPSが頭打ちになり、テールレイテンシやエラーが増え始める地点が、そのエンドポイントの飽和点の目安です。

abが適切なツールでなくなる場合

ab は便利ですが、用途は狭いです。次のケースでは別のツールを検討してください。

1実行につき1つのURLしか扱えない

ab は単一エンドポイントだけをテストします。

例えば、次のようなフローは扱えません。

  1. ログインする
  2. トークンを取得する
  3. リソースを作成する
  4. 作成したリソースを取得する
  5. 更新する

実ユーザーの操作は複数エンドポイントを順番に呼び出すことが多いため、そのようなシナリオには向いていません。

レスポンスの正しさを検証しない

ab はステータスコードやレスポンスサイズを数えますが、JSONの中身は検証しません。

例えば、次のような問題は検出できません。

  • 必須フィールドが欠けている
  • 型が間違っている
  • スキーマに違反している
  • 値が期待と異なる

負荷テストの前に、通常条件でAPIが正しいレスポンスを返すことを別途確認する必要があります。

HTTP/2をサポートしない

公式ドキュメントによると、ab はHTTP/1.xも完全には実装していません。HTTP/2はサポートしていません。

HTTP/2での挙動が重要なAPIでは、HTTP/2対応の負荷テストツールを使う必要があります。

単一マシンからの負荷に限られる

ab は1つのマシン、1つのプロセスから負荷をかけます。

同時実行数を大きくしすぎると、サーバーではなく、ab を実行しているクライアント側がボトルネックになることがあります。

多段階シナリオや分散負荷が必要な場合は、JMeter のようなツールを検討できます。選択肢を比較したい場合は、負荷テストツールのまとめ も参考になります。

機能テストと組み合わせる

スループットは重要ですが、それだけではAPI品質を判断できません。APIは速いだけでなく、正しいレスポンスを返す必要があります。

ab は負荷を測るツールです。正確性の検証は、機能テストや契約テストで行います。

Apidog を使うと、次のようなAPIテストシナリオを作成できます。

  • 視覚的なアサーションを使った検証
  • 複数リクエストをつなげたシナリオ
  • レスポンスのスキーマ検証
  • 保存したシナリオの再利用

これらは ab が設計上扱わない領域です。

Apidog CLIでCIに組み込む

CIで保存済みシナリオを実行する場合は、Apidog CLIを使えます。

まず、Node環境にCLIをインストールします。

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

次に、保存済みのシナリオまたはスイートを指定して実行します。

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

主なフラグは次の通りです。

  • -t: 保存済みシナリオ、フォルダー、またはスイートのID
  • -e: 実行環境のID
  • -r: レポーター。clihtmljsonjunit などを指定可能
  • -d / --iteration-data: データ駆動テスト用のデータファイルパスまたはテストデータID

例えば、CIでJUnitレポートを保存したい場合は、次のような流れになります。

npm install -g apidog-cli

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

健全な構成では、次のように役割を分けます。

  1. Apidogで機能テストを実行し、APIが正しいことを確認する
  2. ab で単一エンドポイントのスループットとレイテンシを測定する

正確性とパフォーマンスの両面を扱いたい場合は、ApidogのパフォーマンステストガイドAPIパフォーマンステストチュートリアル も参照してください。

よくある質問

ApacheBenchはApacheサーバー専用ですか?

いいえ。ab は通常のHTTP/HTTPSリクエストを送るクライアントです。Nginx、Node.js、Go、Pythonなど、HTTPを話すサーバーであればテストできます。

Apacheとの関係は、ab がApache HTTP Serverに同梱されているという点だけです。

どの同時実行数とリクエスト数を使うべきですか?

低い値から始めて段階的に上げます。

例:

ab -n 1000 -c 10 -k https://api.example.com/v1/users
ab -n 1000 -c 25 -k https://api.example.com/v1/users
ab -n 1000 -c 50 -k https://api.example.com/v1/users
ab -n 1000 -c 100 -k https://api.example.com/v1/users
Enter fullscreen mode Exit fullscreen mode

RPSが伸びなくなり、95p / 99pレイテンシやエラーが増える点を確認してください。その地点が、おおよその飽和点です。

APIは正常なのにFailed requestsが多いのはなぜですか?

ab はレスポンス長がリクエスト間で異なると、失敗として扱うことがあります。動的なJSONレスポンスでは、レスポンスサイズが変わるのは自然です。

その場合は -l を追加します。

ab -n 1000 -c 50 -k -l https://api.example.com/v1/users
Enter fullscreen mode Exit fullscreen mode

そのうえで、Non-2xx responses を確認し、実際のHTTPエラーが発生していないかを見てください。

abはログインが必要なエンドポイントをテストできますか?

トークンをすでに持っている場合は可能です。

ab -n 500 -c 25 -k \
  -H "Authorization: Bearer YOUR_TOKEN" \
  https://api.example.com/v1/me
Enter fullscreen mode Exit fullscreen mode

ただし、ab はログインしてトークンを取得し、そのトークンを次のリクエストで使うような多段階フローは実行できません。その場合は、Apidogのようなシナリオベースのツールが必要です。

abはHTTP/2をサポートしていますか?

いいえ。ab はHTTP/1.x向けのツールで、HTTP/2はサポートしていません。

HTTP/2での性能や挙動を測定したい場合は、HTTP/2対応の負荷テストツールを使ってください。

Top comments (0)