Open16

パフォーマンステストについてお勉強

もっくま(Mistletoe)もっくま(Mistletoe)

Q:バックエンドAPIのパフォーマンステストを実施しようと考えています。まずはテスト計画をたてようと考えているのですが、どのような形でテスト計画を実施すると良さそうでしょうか?

# APIパフォーマンステスト計画書

## 1. テスト目的
- システムの性能要件の検証
- ボトルネックの特定
- システムの限界値の把握
- 本番環境での予想負荷への耐性確認

## 2. テスト対象
### 2.1 テスト環境
- テスト環境の詳細(ハードウェア/ソフトウェア構成)
- ネットワーク構成
- データベース設定
- キャッシュ設定

### 2.2 テスト対象API
- 重要度の高いエンドポイント
- リソース消費の大きいエンドポイント
- 頻繁に使用されるエンドポイント
- バッチ処理を伴うエンドポイント

## 3. テスト種類
### 3.1 負荷テスト
- 通常の予想負荷でのパフォーマンス計測
- 段階的な負荷上昇時の振る舞い確認
- 目標とするレスポンスタイム達成の確認

### 3.2 ストレステスト
- システムの限界値の特定
- 急激な負荷上昇時の挙動確認
- エラー発生時の回復性確認

### 3.3 耐久性テスト
- 長時間の継続的負荷での安定性確認
- メモリリークの検出
- パフォーマンス低下の有無確認

## 4. 測定指標
### 4.1 基本指標
- レスポンスタイム(平均、最大、最小、90パーセンタイル)
- スループット(RPS/TPS)
- エラー率
- CPU使用率
- メモリ使用率
- ディスクI/O
- ネットワーク使用率

### 4.2 アプリケーション固有指標
- データベースのコネクション数
- キャッシュヒット率
- トランザクション成功率
- ガベージコレクション頻度と時間

## 5. テストシナリオ
### 5.1 負荷テストシナリオ
1. 通常負荷テスト
   - ユーザー数: 通常時の予想最大ユーザー数
   - 期間: 1時間
   - 目標レスポンスタイム: ○○ms以内

2. ピーク負荷テスト
   - ユーザー数: ピーク時の予想最大ユーザー数
   - 期間: 30分
   - 目標レスポンスタイム: ○○ms以内

### 5.2 ストレステストシナリオ
1. 限界値テスト
   - ユーザー数: 段階的に増加(10→100→1000→...)
   - 期間: 各段階15分
   - 測定: システムの限界値を特定

2. 回復性テスト
   - 急激な負荷上昇と下降の繰り返し
   - 期間: 2時間
   - 測定: システムの回復性能

### 5.3 耐久性テストシナリオ
- ユーザー数: 通常負荷の80%
- 期間: 24時間
- 測定: 性能低下やメモリリークの有無

## 6. テスト実行計画
### 6.1 事前準備
- テスト環境の構築
- テストデータの準備
- モニタリングツールの設定
- テストツールの選定と設定(JMeter、k6、Gatling等)

### 6.2 実行スケジュール
1. 予備テスト: 1日
2. 負荷テスト: 2日
3. ストレステスト: 2日
4. 耐久性テスト: 2日
5. 結果分析とレポート作成: 2日

### 6.3 実行条件
- テスト実行時間帯
- バックアップのタイミング
- 監視体制
- 中断基準

## 7. 成功基準
### 7.1 性能要件
- レスポンスタイム: 90%のリクエストが○○ms以内
- スループット: ピーク時○○RPS以上
- エラー率: ○○%以下
- CPU使用率: ○○%以下
- メモリ使用率: ○○%以下

### 7.2 安定性要件
- 24時間テストでの性能低下なし
- クラッシュやハングアップの発生なし
- メモリリークの発生なし

## 8. 報告体制
### 8.1 報告項目
- テスト結果サマリー
- 詳細な測定データ
- 問題点と改善提案
- グラフや図表による可視化

### 8.2 報告先
- プロジェクトマネージャー
- 開発チーム
- インフラチーム
- その他ステークホルダー

## 9. リスクと対策
### 9.1 想定されるリスク
- テスト環境の不具合
- テストツールの限界
- 予期せぬシステム障害
- テストデータの不足

### 9.2 対策
- バックアップ体制の整備
- 代替ツールの準備
- 緊急連絡体制の確立
- 追加テストデータの準備
このテスト計画書を参考に、以下の手順で具体的な計画立案を進めることをお勧めします:

テスト目的の明確化


具体的な性能要件の数値目標を設定
重要なボトルネックポイントの特定
システムの限界値の定義


テスト範囲の特定


重要なAPIエンドポイントのリストアップ
テストに必要なリソースの見積もり
テスト環境の要件定義


テストシナリオの詳細化


実際のユースケースに基づいたシナリオ作成
データ依存関係の考慮
エラーケースの包含


実行計画の具体化


詳細なスケジュール策定
必要なツールの選定
役割分担の明確化

テスト計画を実施する際の重要なポイントをいくつか補足させていただきます:

段階的なアプローチ:小規模なテストから開始し、徐々に規模を拡大することで、早期に問題を発見できます。
モニタリング体制:テスト中のシステムの状態を適切に監視できる体制を整えることが重要です。
データの準備:テストに必要な十分なテストデータを事前に用意することで、より現実的なテスト結果が得られます。

テスト計画の詳細な部分について、さらにアドバイスが必要な場合はお申し付けください。また、特定の領域(例:負荷テストツールの選定、モニタリング方法など)についても、より具体的なアドバイスが可能です。
もっくま(Mistletoe)もっくま(Mistletoe)

例えばどんなテストシナリオ・ケースが考えられるかな

Q: 挙げられている3つのテスト種類について、どのようなシナリオがあるか、具体例を上げてみてください。

3つのテスト種類(負荷テスト、ストレステスト、耐久性テスト)について、具体的なシナリオ例を作成させていただきます。
# APIパフォーマンステストシナリオ例

## 1. 負荷テスト(Load Test)シナリオ

### シナリオ1: ECサイトの商品検索・商品詳細表示
**目的**: 通常の営業時間帯における一般的なユーザー行動のシミュレーション

**シナリオの流れ**:
1. GET /api/products (商品一覧取得)
2. GET /api/products?category=electronics (カテゴリ検索)
3. GET /api/products/{id} (商品詳細取得)
4. GET /api/products/{id}/reviews (商品レビュー取得)

**テストパラメータ**:
- 同時接続ユーザー数: 1000人
- ランプアップ期間: 5分
- テスト持続時間: 30分
- インターバル: リクエスト間で2-5秒のランダム待機
- 期待値: レスポンスタイム95パーセンタイルで200ms以内

### シナリオ2: ユーザー認証・決済処理
**目的**: セキュアなエンドポインでの処理性能の検証

**シナリオの流れ**:
1. POST /api/auth/login (ログイン)
2. GET /api/users/profile (プロフィール取得)
3. POST /api/cart/checkout (決済処理)
4. GET /api/orders/status (注文状態確認)

**テストパラメータ**:
- 同時接続ユーザー数: 500人
- ランプアップ期間: 3分
- テスト持続時間: 20分
- 決済処理成功率: 99.9%以上
- 期待値: レスポンスタイム90パーセンタイルで500ms以内

## 2. ストレステスト(Stress Test)シナリオ

### シナリオ1: 大規模セール開始時のアクセス集中
**目的**: 急激なアクセス増加時のシステム挙動確認

**シナリオの流れ**:
1. GET /api/sale/products (セール商品一覧)
2. POST /api/cart/add (カート追加)
3. POST /api/orders/create (注文作成)
4. GET /api/orders/{id} (注文確認)

**テストパラメータ**:
- 初期ユーザー数: 100人
- 最大ユーザー数: 10,000人
- ランプアップ: 1分ごとに1,000人ずつ増加
- テスト持続時間: 15分
- 監視項目: 
  - サーバーレスポンスタイム
  - データベース接続数
  - メモリ使用率
  - エラーレート

### シナリオ2: データ集計処理の限界値テスト
**目的**: バッチ処理やレポート生成時の処理限界の把握

**シナリオの流れ**:
1. POST /api/reports/generate (レポート生成開始)
2. GET /api/reports/status (生成状態確認)
3. GET /api/reports/download (レポートダウンロード)

**テストパラメータ**:
- 同時リクエスト数: 10→50→100→500→1000
- 各段階の持続時間: 5分
- データ量: 10MB→100MB→1GB
- 監視項目:
  - CPUリソース使用率
  - メモリ消費量
  - ディスクI/O
  - 処理完了率

## 3. 耐久性テスト(Endurance Test)シナリオ

### シナリオ1: 日常的なAPI利用パターン
**目的**: 長時間の通常使用における性能劣化やリソースリークの検出

**シナリオの流れ**:
1. GET /api/dashboard (ダッシュボード情報取得)
2. POST /api/data/update (データ更新)
3. GET /api/notifications (通知取得)
4. GET /api/stats (統計情報取得)

**テストパラメータ**:
- テスト期間: 24時間
- 同時接続ユーザー数: 200人(通常負荷の80%)
- リクエスト間隔: 平均30秒
- 監視項目:
  - メモリ使用量の推移
  - レスポンスタイムの変化
  - データベースコネクション数
  - キャッシュヒット率
  - ログファイルサイズ

### シナリオ2: 継続的なデータ同期処理
**目的**: 定期的なバッチ処理やデータ同期の安定性確認

**シナリオの流れ**:
1. POST /api/sync/start (同期開始)
2. GET /api/sync/status (同期状態確認)
3. GET /api/sync/logs (同期ログ取得)
4. POST /api/sync/validate (データ整合性チェック)

**テストパラメータ**:
- テスト期間: 48時間
- 同期間隔: 15分
- データ量: 1回あたり50MB
- 監視項目:
  - 同期処理の成功率
  - 処理時間の推移
  - リソース使用率の変化
  - エラーログの蓄積
  - ディスク使用量の推移

## 各シナリオ共通の考慮事項

### 1. データ準備
- テストデータのバリエーション
- データ量の調整
- テストユーザーアカウント
- 初期状態のリセット方法

### 2. 監視項目
- インフラメトリクス(CPU、メモリ、ディスクI/O)
- アプリケーションメトリクス(レスポンスタイム、エラー率)
- データベースメトリクス(クエリ実行時間、コネクション数)
- ネットワークメトリクス(スループット、レイテンシ)

### 3. 異常検知条件
- レスポンスタイムの急激な上昇(例:平均の2倍以上)
- エラー率の上昇(例:1%以上)
- メモリ使用率の継続的な増加
- CPU使用率の閾値超過(例:80%以上)

### 4. 中断条件
- エラー率が5%を超えた場合
- レスポンスタイムが設定値の3倍を超えた場合
- メモリ使用率が95%を超えた場合
- ディスク空き容量が10%を下回った場合
これらのシナリオ例について、いくつか重要なポイントを補足させていただきます:

負荷テストについて


実際のユーザー行動を模したシナリオ設計が重要です
段階的な負荷増加により、システムの応答性の変化を観察できます
複数の関連APIを組み合わせることで、より現実的なテストが可能です


ストレステストについて


システムの限界値を見極めるために、意図的に高負荷をかけます
エラー発生時の挙動やリカバリー性能も確認できます
特に重要なのは、急激な負荷変動への対応能力の確認です


耐久性テストについて


長時間の安定動作を確認することが主目的です
メモリリークやリソース枯渇の早期発見が可能です
定期的なバッチ処理との相互作用も確認できます

これらのシナリオは、あくまでも例示であり、実際のシステムに合わせてカスタマイズが必要です。特に以下の点について、調整を検討することをお勧めします:

テスト対象のAPIの特性に応じた負荷パターン
実際の利用状況に基づいたユーザー数やリクエスト頻度
システムの要件に基づいた期待値の設定
監視項目やアラート条件の調整

具体的なシナリオの作成やカスタマイズについて、さらにアドバイスが必要な場合はお申し付けください。
もっくま(Mistletoe)もっくま(Mistletoe)

テストフレームワークを調べよう。

Gensparkにとりあえず聞いてみた。

Feloでも聞いてみた。こっちのが優秀かもかも。


以下は、APIに対する負荷テストやストレステストに利用される主要なテストフレームワークのリストに、定量的な比較項目を追加した表です。これにより、各ツールの性能や機能をより具体的に比較できるようになります。

ツール名 説明 言語/プラットフォーム 特徴/差別化要素 最大同時ユーザー数 スクリプト記述方法 レポート機能 価格
JMeter Javaベースのオープンソースツールで、負荷テストやストレステストに広く使用される。HTTP、FTPなどのプロトコルをサポート。 Java プロトコルのサポートが豊富で、プラグインが充実。GUIでの操作が可能で、視覚的なレポート生成が得意。 数千〜数万 GUI/ XML 詳細なグラフと統計 無料(オープンソース)
Gatling ScalaとAkkaを基にした高性能な負荷テストツール。シナリオをコードで記述可能。 Scala 高いパフォーマンスを誇り、DSLを使用してシナリオを簡潔に記述できる。自動レポート生成機能もあり。 数万 Scala DSL 自動生成 無料(オープンソース)
Locust Pythonで書かれたオープンソースの負荷テストツール。ユーザー行動をPythonコードで定義し、同時に多数のユーザーをシミュレート。 Python 分散実行が可能で、WebベースのUIを持ち、リアルタイムで進行状況を確認できる。カスタマイズ性が高い。 数万 Python リアルタイム 無料(オープンソース)
K6 JavaScriptで記述された負荷テストツール。シンプルなスクリプトで高いパフォーマンスを提供。 JavaScript CLIベースで使いやすく、リアルタイムモニタリングが可能。軽量で、スクリプトの記述が直感的。 数千〜数万 JavaScript リアルタイム 無料(オープンソース)
LoadRunner 商用の負荷テストツールで、複数のプロトコルをサポートし、詳細なレポート機能を持つ。 複数のプラットフォーム 幅広いプロトコルに対応し、企業向けの強力な分析機能を提供。高い信頼性とサポートが特徴。 数万〜数十万 GUI/ C 詳細なグラフと統計 商用ライセンス(高額)
Artillery YAMLでシナリオを記述することができるオープンソースの負荷テストツール。リアルタイムのレポート機能を提供。 JavaScript シンプルな設定で、スケーラブルなテストが可能。リアルタイムでの結果表示が強み。 数千 YAML リアルタイム 無料(オープンソース)
BlazeMeter JMeterのクラウドベースの拡張で、スケーラブルな負荷テストを提供。 Web JMeterの機能をクラウドで利用でき、スケーラビリティが高い。複数のテストを同時に実行可能。 数十万 GUI/ JMeter 詳細なグラフと統計 商用ライセンス(従量課金)
Postman 主にAPIテストに使用されるが、負荷テスト機能も追加されている。ユーザーフレンドリーなインターフェースを持つ。 Web APIの機能テストに強みがあり、負荷テストも簡単に実施できる。直感的なUIで使いやすい。 数百〜数千 GUI/ JavaScript 基本的なレポート 無料プランあり(有料プランも)

この表は、各ツールの性能や機能を定量的に比較できるように設計されています。最大同時ユーザー数やスクリプト記述方法、レポート機能、価格などの情報を含めることで、利用するフレームワークの選定に役立つでしょう。特に、負荷テストの規模やチームの技術スタックに応じて最適なツールを選ぶことが重要です[1][2][4].
[1] https://apidog.com/jp/blog/best-15-testing-frameworks/
[2] https://qiita.com/takuya77088/items/5531332bf3f646865b91
[3] https://www.zaptest.com/ja/モバイルアプリのテスト-その内容、種類、プロ
[4] https://apidog.com/jp/blog/top-tools-unlimited-collection-runner/
[5] https://docs.aws.amazon.com/ja_jp/wellarchitected/2024-06-27/framework/wellarchitected-framework-2024-06-27.pdf
[6] https://note.com/vast_cosmos500/n/nfc3ee4cea095
[7] https://aster.or.jp/business/testtool_wg/pdf/Testtool_beginningGuide_Version1.0.0.pdf
[8] https://herp.careers/v1/findy
[9] https://www.mlit.go.jp/pri/houkoku/gaiyou/pdf/kkk174.pdf
[10] https://docs.aws.amazon.com/ja_jp/wellarchitected/2023-10-03/framework/wellarchitected-framework-2023-10-03.pdf

もっくま(Mistletoe)もっくま(Mistletoe)

技術選定的観点でいうとテスト要件や使用環境とかで変わりそう。
もっと言うと使いやすさは使わないと分からないかな。

もっくま(Mistletoe)もっくま(Mistletoe)

k6 new を打つとscript.jsファイルが生成された。

中身↓

script.js
import http from 'k6/http';
import { sleep } from 'k6';

export const options = {
  // A number specifying the number of VUs to run concurrently.
  vus: 10,
  // A string specifying the total duration of the test run.
  duration: '30s',

  // The following section contains configuration options for execution of this
  // test script in Grafana Cloud.
  //
  // See https://grafana.com/docs/grafana-cloud/k6/get-started/run-cloud-tests-from-the-cli/
  // to learn about authoring and running k6 test scripts in Grafana k6 Cloud.
  //
  // cloud: {
  //   // The ID of the project to which the test is assigned in the k6 Cloud UI.
  //   // By default tests are executed in default project.
  //   projectID: "",
  //   // The name of the test in the k6 Cloud UI.
  //   // Test runs with the same name will be grouped.
  //   name: "script.js"
  // },

  // Uncomment this section to enable the use of Browser API in your tests.
  //
  // See https://grafana.com/docs/k6/latest/using-k6-browser/running-browser-tests/ to learn more
  // about using Browser API in your test scripts.
  //
  // scenarios: {
  //   // The scenario name appears in the result summary, tags, and so on.
  //   // You can give the scenario any name, as long as each name in the script is unique.
  //   ui: {
  //     // Executor is a mandatory parameter for browser-based tests.
  //     // Shared iterations in this case tells k6 to reuse VUs to execute iterations.
  //     //
  //     // See https://grafana.com/docs/k6/latest/using-k6/scenarios/executors/ for other executor types.
  //     executor: 'shared-iterations',
  //     options: {
  //       browser: {
  //         // This is a mandatory parameter that instructs k6 to launch and
  //         // connect to a chromium-based browser, and use it to run UI-based
  //         // tests.
  //         type: 'chromium',
  //       },
  //     },
  //   },
  // }
};

// The function that defines VU logic.
//
// See https://grafana.com/docs/k6/latest/examples/get-started-with-k6/ to learn more
// about authoring k6 scripts.
//
export default function() {
  http.get('https://test.k6.io');
  sleep(1);
}
もっくま(Mistletoe)もっくま(Mistletoe)

中身をCursorで解説させる。


k6のテストスクリプトについて説明させていただきます。

このスクリプトは負荷テストを実行するための基本的な設定を含んでいます。主な内容は:

  1. 基本設定:

    • vus: 10 - 同時に10個の仮想ユーザー(Virtual Users)を実行
    • duration: '30s' - テストを30秒間実行
  2. コメントアウトされた設定オプション:

    • Grafana Cloudでの実行設定
    • ブラウザAPIを使用するためのシナリオ設定
  3. テストロジック:

    • シンプルなGETリクエストをhttps://test.k6.ioに対して実行
    • 各リクエスト後に1秒間の待機時間を設定

このスクリプトは以下のように動作します:

  • 10人の仮想ユーザーが同時に
  • 30秒間にわたって
  • test.k6.ioに対してGETリクエストを繰り返し実行
  • 各リクエストの間に1秒の間隔を置く

これは負荷テストの基本的なテンプレートとして使用でき、必要に応じて:

  • リクエスト数の調整
  • テスト時間の変更
  • より複雑なシナリオの追加
  • Grafana Cloudとの統合
  • ブラウザベースのテスト

などの拡張が可能です。

もっくま(Mistletoe)もっくま(Mistletoe)

k6 run script.js で試しに動かす。


動いとる動いとる。


最終的には以下が出力された↓


         /\      Grafana   /‾‾/
    /\  /  \     |\  __   /  /
   /  \/    \    | |/ /  /   ‾‾\
  /          \   |   (  |  (‾)  |
 / __________ \  |_|\_\  \_____/

     execution: local
        script: script.js
        output: -

     scenarios: (100.00%) 1 scenario, 10 max VUs, 1m0s max duration (incl. graceful stop):
              * default: 10 looping VUs for 30s (gracefulStop: 30s)


     data_received..................: 2.9 MB 96 kB/s
     data_sent......................: 28 kB  910 B/s
     http_req_blocked...............: avg=20.02ms  min=3µs      med=6µs      max=513.01ms p(90)=8µs      p(95)=30.09µs
     http_req_connecting............: avg=7.28ms   min=0s       med=0s       max=190.68ms p(90)=0s       p(95)=0s
     http_req_duration..............: avg=193.31ms min=171.22ms med=180.93ms max=362.73ms p(90)=186.98ms p(95)=351.87ms
       { expected_response:true }...: avg=193.31ms min=171.22ms med=180.93ms max=362.73ms p(90)=186.98ms p(95)=351.87ms
     http_req_failed................: 0.00%  0 out of 250
     http_req_receiving.............: avg=13.43ms  min=35µs     med=72µs     max=178.75ms p(90)=946.09µs p(95)=174.49ms
     http_req_sending...............: avg=22.25µs  min=8µs      med=20µs     max=148µs    p(90)=29.09µs  p(95)=44.64µs
     http_req_tls_handshaking.......: avg=7.96ms   min=0s       med=0s       max=204.49ms p(90)=0s       p(95)=0s
     http_req_waiting...............: avg=179.85ms min=171.13ms med=180.07ms max=219.32ms p(90)=184.38ms p(95)=185.25ms
     http_reqs......................: 250    8.145568/s
     iteration_duration.............: avg=1.21s    min=1.17s    med=1.18s    max=1.69s    p(90)=1.35s    p(95)=1.36s
     iterations.....................: 250    8.145568/s
     vus............................: 10     min=10       max=10
     vus_max........................: 10     min=10       max=10


running (0m30.7s), 00/10 VUs, 250 complete and 0 interrupted iterations
default ✓ [======================================] 10 VUs  30s
もっくま(Mistletoe)もっくま(Mistletoe)

Claudeに結果を要約させた。


k6の負荷テスト結果について詳しく解析していきましょう。
まず、テストの基本設定と概要について説明します:

テスト設定:

実行時間: 30秒間
同時ユーザー数(VU): 10人
総リクエスト数: 250回
リクエスト頻度: 約8.15リクエスト/秒

主要なパフォーマンス指標の詳細分析:

a) レスポンスタイム (http_req_duration):

平均: 193.31ms
最小: 171.22ms
中央値: 180.93ms
最大: 362.73ms
90パーセンタイル: 186.98ms
95パーセンタイル: 351.87ms

b) 待機時間の内訳:

コネクション確立 (http_req_connecting): 平均7.28ms
TLSハンドシェイク (http_req_tls_handshaking): 平均7.96ms
リクエスト送信 (http_req_sending): 平均22.25µs
サーバー処理待ち (http_req_waiting): 平均179.85ms
レスポンス受信 (http_req_receiving): 平均13.43ms

以下のグラフで視覚化してみましょう:K6 Performance Test Results VisualizationClick to open component
重要な観察事項:

a) 信頼性:

エラー率: 0% (http_req_failed: 0.00%)
全てのリクエストが期待通りのレスポンスを返却

b) パフォーマンスの特徴:

レスポンスタイムの一貫性が比較的高い(最小171msから最大362ms)
サーバー処理時間(http_req_waiting)が全体の約93%を占める
ネットワーク関連の遅延は比較的小さい

データ転送:

受信データ: 2.9 MB (96 kB/s)
送信データ: 28 kB (910 B/s)

改善提案:

このテスト結果から、以下の改善ポイントが考えられます:

サーバー処理時間の最適化:

処理時間が全体の93%を占めているため、ここを改善することで最も効果が高い
特に95パーセンタイルでの急激な上昇(351.87ms)に注目

コネクション管理:

コネクション確立とTLSハンドシェイクで合計約15msかかっている
Keep-Alive設定の最適化を検討

スケーラビリティテスト:

現在の10VUでは安定しているが、より多くの同時接続数でのテストを推奨

このテスト結果は全体的に良好で、システムは安定して動作していることを示しています。ただし、実際の本番環境での負荷に備えて、より高い同時接続数でのテストも検討することをお勧めします。