エンドポイントをリリースしました。ブラウザでは動作します。しかし、400人が同時にアクセスしたときに何が起こるか、あなたは全く知りません。レイテンシは一定のままですか、それとも99パーセンタイルは跳ね上がりますか?そのボックスは毎秒1,000リクエストを処理できますか、それとも300で落ちてしまいますか?
wrkがそれに答えます。これは、URLに大量のHTTPトラフィックを発生させ、その負荷の下でサーバーがどれだけ速く応答したかを報告する小さなコマンドラインツールです。
wrkとは何か、そしていつ使うべきか
wrkは最新のHTTPベンチマークツールです。単一のマルチコアマシンから負荷を生成し、サーバーが返すレイテンシとリクエストレートを測定します。マルチスレッドとスケーラブルなイベントループ(Linuxではepoll、macOSではkqueue)を使用するため、1つのインスタンスで多数の負荷生成ボックスを必要とせずに大量のトラフィックをプッシュできます。
生のパフォーマンス数値が必要な場合は、wrkを利用しましょう。
- このエンドポイントは毎秒何件のリクエストを処理できますか?
- 中央値とテールのレイテンシはどのようになりますか?
- サーバーは持続的な期間持ちこたえますか、それとも1分後に性能が低下しますか?
wrkはベンチマークツールであり、テストスイートではありません。速度を測定します。JSONボディが正しいか、ステータスコードが200であるか、API契約が維持されているかを確認しません。この区別を心に留めておいてください。実際のテストワークフローにwrkをどのように組み込むかという点で重要になるため、この点については後で詳しく説明します。まず全体像を把握したい場合は、このAPI負荷テストガイドがwrkが実践する概念をカバーしています。
wrkのインストール
macOS
Homebrewにはビルド済みのバイナリがあり、これが最も簡単な方法です。
brew install wrk
Apple Siliconではこれが重要です。ソースからビルドするとLuaJIT ARM64の問題に遭遇する可能性があり、Homebrewのバイナリを使用すればその手間を省けます。
Linux (ソースからビルド)
公式のaptパッケージがないため、自分でビルドします。まずツールチェーンとOpenSSLヘッダーをインストールしてください。
sudo apt-get install build-essential libssl-dev git -y
次にクローンしてコンパイルします。
git clone https://github.com/wg/wrk.git
cd wrk
make
これにより、現在のディレクトリにwrkバイナリが生成されます。どこからでも呼び出せるように、PATHに移動してください。
sudo cp wrk /usr/local/bin
実行できることを確認します。
wrk --version
基本的なコマンド
wrkの実行は常にこのような形になります。
wrk -t12 -c400 -d30s http://127.0.0.1:8080/index.html
4つのことが行われています。フラグを詳しく見ていきましょう。
-t, --threadsは、wrkが起動するOSスレッドの数を設定します。良い開始点は、CPUコアあたり1つのスレッドです。ここでは12です。-c, --connectionsは、すべてのスレッドで開かれるHTTP接続の総数を設定します。ここでは400の接続が12のスレッドに分散されます。接続は、同時クライアントをシミュレートする方法です。-d, --durationは、テストの実行時間を設定します。30s、2m、2hのような値を受け入れます。ここでは30秒です。
常に使用するフラグがさらに2つあります。
--latencyは、詳細なレイテンシパーセンタイル内訳を出力します。ほとんどの場合、これをオンにしてください。平均値はテールレイテンシを隠しがちですが、通常、ユーザーを苦しめるのはテールです。--timeoutは、設定した時間内に応答がない場合、リクエストをタイムアウトとして記録します(例:--timeout 2s)。これがないと、遅い応答がレイテンシの数値を歪める可能性があります。
よく利用する実行コマンドは次のようになります。
wrk -t8 -c200 -d30s --latency http://localhost:3000/api/users
8つのスレッド、200の接続、30秒間実行し、最後に完全なレイテンシ分布が出力されます。
出力の読み方
wrkは簡潔なレポートを出力します。小規模なサービスに対する実際の実行例です。
Running 5s test @ http://10.135.232.163:3000
2 threads and 5 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 3.82ms 2.64ms 26.68ms 85.81%
Req/Sec 550.90 202.40 0.98k 68.00%
5494 requests in 5.01s, 1.05MB read
Requests/sec: 1096.54
Transfer/sec: 215.24KB
下から上に読んでください。最後の2行が主な結果だからです。
Requests/sec はスループットです。サーバーが平均して1秒あたりに完了したリクエスト数を示します。ここでは1,096です。これは、異なる実行間やコード変更間で比較する数値です。
Transfer/sec は帯域幅です。1秒あたりに転送されたデータ量を示します。ペイロードが大きい場合や、CPUバウンドではなく帯域幅がボトルネックになっていると思われる場合に役立ちます。
次に、平均値だけでなく分布を説明するThread Stats テーブルです。
- Latency 行: 平均レイテンシは3.82msでしたが、標準偏差は2.64msで、最大値は26.68msに急上昇しました。平均値に対して最大値が高いのは兆候です。ほとんどのリクエストが高速でも、一部のリクエストは遅いことがあります。
- Req/Sec 行: スレッドごとのリクエストレートで、これもそのばらつきを示しています。
+/- Stdev 列は、サンプルのうち1標準偏差内に収まった割合を示します。割合が低いほど、ばらつきが大きく、予測しにくいことを意味します。
5494 requests in 5.01s の行は、実際に実行がプッシュした総リクエスト量を確認します。
--latency を追加すると、wrkはパーセンタイルブロックを出力し、テールを直接確認できます。
Latency Distribution
50% 3.21ms
75% 4.86ms
90% 7.09ms
99% 14.13ms
99パーセンタイルは注目すべき数値です。99%のリクエストが14msで完了しても、平均が3.82msであれば、100人のユーザーのうち1人は平均が示唆するよりもはるかに長く待っていることになります。平均値はテールについて嘘をつきますが、パーセンタイルはそうではありません。
LuaスクリプトでPOSTリクエストとカスタムヘッダーを送信する
デフォルトでは、wrkはGETリクエストを送信します。POSTを送信したり、ボディを追加したり、カスタムヘッダーを設定したりするには、-s オプションでLuaスクリプトを渡します。
post.luaという名前のファイルを作成します。
wrk.method = "POST"
wrk.body = '{"name": "Ada", "role": "engineer"}'
wrk.headers["Content-Type"] = "application/json"
3つのフィールドが機能します。wrk.method はHTTP動詞を設定します。wrk.body はリクエストボディを設定します。wrk.headers は、各キーがヘッダー名であるテーブルです。
スクリプトに-sを向けて実行します。
wrk -t4 -c100 -d30s -s post.lua --latency http://localhost:3000/api/users
JSONではなくフォームエンコードされたPOSTの場合、wrkリポジトリにはこの正確な例が同梱されています。
wrk.method = "POST"
wrk.body = "foo=bar&baz=quux"
wrk.headers["Content-Type"] = "application/x-www-form-urlencoded"
より単純なケースでは、スクリプトなしで-Hフラグを使用してヘッダーを設定することもできます。
wrk -t4 -c100 -d30s -H "Authorization: Bearer TOKEN123" --latency http://localhost:3000/api/protected
1つか2つのヘッダーには-Hを使用します。ボディ、GET以外のメソッド、またはリクエストごとのロジックが必要な場合は、Luaスクリプトを使用します。
制限事項:wrkは正しさをチェックしない
これは人々が見落としがちな部分です。wrkはサーバーがどれだけ速く応答したかを教えてくれますが、その応答が正しかったかどうかは教えてくれません。
すべてのリクエストでHTTP 500を返すエンドポイントにwrkを向けても、高いRequests/secの数値を持つきれいに見えるレポートが得られます。wrkは完了したHTTP交換を数えます。ステータスコードをアサートしたり、応答ボディをスキーマに対して検証したり、APIが意図したとおりに動作したことを確認したりはしません。サーバーがリクエストを早期に拒否する場合、1リクエストあたりの作業が少ないため、エラーでさえ高速に見えることがあります。
したがって、wrkは「負荷の下で十分に速いか?」という問いには答えます。「正しいか?」という問いには答えられません。どちらの質問も重要であり、異なるツールが必要です。壊れたエンドポイントの負荷数値は信頼すべきではありません。まさにこの理由から、チームはベンチマークツールと機能テストスイートを組み合わせます。一方は速度を証明し、もう一方は動作を証明します。
Apidogと機能テストの役割
クリーンなワークフローは、順序通りに実行される2つの層から構成されます。
- まず、動作を検証します。 エンドポイントの速度を気にする前に、それが正しいことを確認してください。Apidogでは、実際のリクエストを送信し、返されるもの(ステータスコード、JSONフィールド、応答スキーマ、ビジネスロジック)をアサートするテストシナリオを構築します。リクエストを連鎖させたり、ステップ間でデータを渡したり、異なる環境で同じシナリオを実行したりできます。これは、wrkが喜んでベンチマークする壊れた500エラーを捕捉する層です。
- 次に、スループットをベンチマークします。 動作が検証されたら、同じエンドポイントに対してwrkを実行し、同時実行と持続的な負荷の下でどのように機能するかを確認します。Apidogには組み込みのパフォーマンステストもあり、機能テストと負荷テストを1か所でまとめて行いたい場合に便利ですが、wrkは生のコマンドラインベンチマークに適した優れた専用ツールです。
機能テスト層は、ラップトップだけでなくCIでも実行されます。Apidog CLIはヘッドレスなので、Nodeを実行できるあらゆるパイプラインステップに組み込むことができます。インストールします。
npm install -g apidog-cli
次に、保存されたテストシナリオまたはスイートをIDで実行します。
apidog run \
--access-token "$APIDOG_ACCESS_TOKEN" \
-t <scenarioOrSuiteId> \
-e <environmentId> \
-r cli,html,junit
-t は実行するシナリオ、フォルダ、またはスイートのIDです。-e は環境IDです。-r はレポート形式(cli、html、json、junitの1つ以上)を選択します。JUnit出力は、ほとんどのCIシステムに直接接続され、合格/不合格のゲートとして機能します。データ駆動型実行の場合、ファイルパスまたはテストデータIDとともに-d(または--iteration-data)を追加して、同じシナリオを多くの入力行で反復します。
CLIは、保存されたApidogのシナリオとスイートを実行します。これはヘッドレスであり、インタラクティブなリクエスト送信ツールではなく、ロードジェネレーターでもありません。これは正しさのゲートです。wrkは速度の測定器です。パイプラインで正しさのゲートを実行し(コピー&ペースト可能な設定については、このCLI CI/CDウォークスルーまたはGitHub Actionsガイドを参照)、スループット数値が必要なときにwrkでベンチマークを実行します。完全なCLIリファレンスには、残りのフラグが記載されています。
よくある質問
wrkとab (ApacheBench)の違いは何ですか? どちらもHTTP負荷を発生させ、毎秒のリクエスト数を報告します。wrkはマルチスレッドでイベントループを使用するため、1台のマシンからより多くの負荷を生成し、高い同時実行性をより良く処理します。abはシングルスレッドです。単一のボックスから重い負荷をかける場合、通常wrkの方がよりスケーラブルです。どちらも応答の正しさをチェックしません。
いくつのスレッドと接続を使用すべきですか? CPUコアあたり1つのスレッドから始め、シミュレートしたい同時実行レベルに接続を設定します。8コアで200の同時クライアントをシミュレートしたい場合、-t8 -c200を試してください。クライアントマシンを監視してください。もしwrk自体がCPUバウンドであれば、あなたの数値はサーバーの限界ではなく、負荷生成器の限界を反映しています。スループットが上昇しなくなるまで接続を増やしてください。
wrkはHTTPSエンドポイントをテストできますか? はい、できます。https:// URLを指すようにすると、wrkはTLSを処理します。これがLinuxビルドでlibssl-devが必要な理由です。TLSハンドシェイクは両端でCPUコストを追加するため、通常のHTTPよりもHTTPSに対する生のスループットは低くなると予想されます。
wrkは応答ボディやステータスコードを検証しますか? いいえ。wrkは完了したHTTP交換を数え、時間を測定します。ステータスコードやボディをアサートしないため、エラーを返すエンドポイントでも高いRequests/secの数値を報告することがあります。Apidog CLIを通じて実行される機能テストスイートなどを使用して正しさを検証し、その後wrkでスループットを測定してください。
負荷テストはどれくらいの期間実行すべきですか? コールドキャッシュやJITコンパイルなどのウォームアップ効果を乗り越えるのに十分な長さです。簡単な確認には数秒で十分ですが、30秒から数分間実行すると、より安定した数値が得られ、持続的な負荷の下でのみ現れる劣化を明らかにできます。健全なデフォルトとして-d30sを使用し、遅いメモリリークなどを追跡している場合は、それを長くしてください。
