三つの問いとAPIパフォーマンステストツールの対応
キャパシティ → 負荷生成ツール
スレッドグループ、ランプアップ、分散ワーカー。
リリース前とアーキテクチャ変更後に実行します。継続的に実行するにはコストがかかります。
リグレッション → 実行時間の比較
必要なのはベースラインと差分であり、高い同時実行数ではありません。
三つの中で最も安価でありながら、最も欠けていることが多い領域です。
正しさ → 機能検証
扱いにくい入力も含めた、レスポンスボディに対するアサーション。
他の二つを支える土台です。
多くのチームに欠けているカテゴリ
パフォーマンステストを実施していると語るチームは、ほぼ例外なく負荷生成ツールを持っています。一方で、変更ごとにリグレッションを監視する仕組みを持つチームはごくわずかです。これはコストの面でも、得られる成果の面でも逆転しています。
キャパシティはリリース間でほとんど変化しないため、継続的に測定してもわかることは多くありません。パフォーマンスのリグレッションは、プルリクエスト単位でひとつずつ入り込みます。四半期ごとのキャパシティ測定でそれを捉えた頃には、半年分のコミットを前にして、どれがインデックスのないクエリを追加したのか見当もつかない状態になっています。
カテゴリごとに確認すべきポイント
負荷生成ツール: せめてサンプルに対してだけでも、レスポンスボディにアサーションをかけられるか。多くのツールは対応していますが、実際に有効にしているチームはわずかです。だからこそ、すべてのレスポンスが空であっても負荷テストは「問題なし」と報告してしまいます。
リグレッション用ツール: 絶対的なしきい値ではなく、自分たちの過去の実績と比較しているか。借り物の目標値は、自社のプロダクトについて何も教えてくれません。
機能検証: 境界値のケースを含んでいるか。ページサイズが大きくなると性能が落ちるクエリは構造的な問題であり、キャパシティテストが表面化させるよりはるかに早く、ここで見つかります。
パーセンタイルをごまかさずに読む
パフォーマンス関連のツールはパーセンタイルを報告しますが、その読み方を誤り、本来探しているはずの問題を覆い隠してしまうことが日常的に起きています。
p50が良好に見えても、それは中央値のリクエストについて語っているだけで、運の悪いユーザーがどんな体験をしているかについては何も語りません。1時間に1000回呼ばれるエンドポイントでp99が良好に見えても、それは1時間あたり10件の遅いリクエストがあるということであり、10人の不満を抱えたユーザーがいるということです。そして全エンドポイントを通じた平均値は、ほとんど無意味です。ヘルスチェックとレポート生成を混ぜてしまうからです。
二つの習慣でほとんどが解決します。パーセンタイルは全体の集計ではなくエンドポイントごとに見ること、そして平均ではなくp95とp99を見ることです。重要なエンドポイントはたいてい数えるほどしかなく、その四つの数値を時系列で追うほうが、すべてを一度に表示するどんなダッシュボードよりも役立ちます。
コストを抑える順序
まず正しさ、次にリグレッション、最後にキャパシティです。誤った結果を返すエンドポイントに負荷テストをかけても、中身のない数値に自信を持つだけであり、これはパフォーマンス施策が最初の四半期を無駄にする最もよくあるパターンです。
ターミナル
npm install -g @testsprite/testsprite-cli
testsprite setup
ローカルに何もインストールしたくない場合は、TestSpriteのダッシュボードからも同じセットアップを行えます。CLIのその他の機能について詳しくは、 CLIリポジトリ。
セッション、取得した値、実行順序、クリーンアップについて詳しくは、 APIテストドキュメント。
方法は二つあり、その選択は実のところ、パイプラインを誰が所有しているかによって決まります。ダッシュボードから GitHub App を接続する方法では、リポジトリに一切変更を加える必要がありません。ビルドがすでに発行しているデプロイに反応するためです。一方、 GitHub Actions のステップを追加する方法では、チェックがリポジトリ内に置かれ、ビルドの他の部分と同じようにレビューを受けられます。
TestSpriteが担う部分
他の二つを支える土台である、正しさの領域です。ステータスコードではなくレスポンスボディに対してアサーションを行い、構造的な遅さを浮かび上がらせる境界値のケースをカバーし、すべてのプルリクエストで実行されます。
カバレッジは、ディスカバリーの実行と仕様書をもとに生成されます。Auto-Authenticationは実行全体を通じてセッションを維持し、Dynamic Variablesは呼び出し間で値を引き継ぎ、Dependency Chainsは実行順序を導き出し、Auto-Cleanupはその実行で作成されたものだけを削除します。
その価値は、キャパシティの数値が、実際に正しく動作しているサービスを表すようになる点にあります。ページサイズが大きくなると性能が落ちるクエリは、負荷テストで見つける場合のごく一部のコストでここで表面化し、黙って空の結果を返しているエンドポイントがスループットで良い数値を出すこともなくなります。
TestSpriteはこのカテゴリに含まれますか?
正しさの領域に含まれます。境界値のケースを含めて挙動を検証しますが、継続的な負荷を生成することはありません。
ひとつのツールで三つすべてをカバーできますか?
そう謳うツールもあります。しかし実際には、負荷を生成することとレスポンスボディを深くアサーションすることは互いに相反します。アサーションは生成側のスループットを消費するからです。
リグレッションのしきい値はどのくらいが妥当ですか?
自分たちのばらつきをもとに決めてください。負荷のかかっていない環境でも実行ごとに数値が10パーセント動くのであれば、5パーセントのしきい値はノイズにすぎません。
分散型の負荷生成は必要ですか?
単一の生成ツールがボトルネックになる場合に限ります。多くのチームは、使い切ることのない分散キャパシティを購入しています。
それぞれどこで実行すべきですか?
正しさとリグレッションはすべてのプルリクエストで。キャパシティはリリース前とアーキテクチャ変更後に。