メインコンテンツにスキップ

Web アプリケーションの負荷テスト戦略: ユーザーがテストを行う前にブレーク ポイントを見つける

k6、Artillery、Locust を使用して Web アプリケーションをロード テストします。テスト設計、トラフィック モデリング、パフォーマンス ベースライン、結果解釈戦略について説明します。

E
ECOSIRE Research and Development Team
|2026年3月16日5 分で読める950 語数|

パフォーマンスの問題の 80% は、テストではなくエンド ユーザーによって発見されます。 負荷テストでは、ユーザーが問題に遭遇する前にアプリケーションに対して現実世界のトラフィック パターンをシミュレートすることで、この比率を逆転させます。ブラック フライデーのトラフィックを処理するサイトとクラッシュするサイトの違いは、ほとんどの場合、誰かが最初に負荷テストを実行したかどうかです。

パフォーマンスとスケーラビリティシリーズの一部

完全ガイドを読む

パフォーマンスの問題の 80% は、テストではなくエンド ユーザーによって発見されます。 負荷テストでは、ユーザーが問題に遭遇する前にアプリケーションに対して現実世界のトラフィック パターンをシミュレートすることで、この比率を逆転させます。ブラック フライデーのトラフィックを処理するサイトとクラッシュするサイトの違いは、ほとんどの場合、誰かが最初に負荷テストを実行したかどうかです。

このガイドでは、Web アプリケーション、e コマース プラットフォーム、ERP システムの負荷テスト方法、ツールの選択、テスト設計、結果の解釈について説明します。

重要なポイント

  • 負荷テストでは、単一のエンドポイントを攻撃するだけでなく、現実的なユーザーの動作をシミュレートする必要があります
  • 最適化する前にパフォーマンスのベースラインを確立する --- 測定していないものを改善することはできません
  • 運用環境に似た環境で負荷テストを実行します。ステージングの結果は本番環境の動作を反映していない可能性があります
  • CI/CD での負荷テストを自動化し、展開前にパフォーマンスの低下を検出します

負荷テストの種類

テストの種類目的期間負荷パターン
煙テスト最小限の負荷で基本機能を検証する1 ~ 2 分1 ~ 5 ユーザー
負荷テスト予想されるトラフィックの下でパフォーマンスを検証する10~30分通常の交通
ストレステスト限界点を見つける15~30分徐々に増加
スパイクテスト突然のトラフィックの急増をテストする5~10分突然のジャンプ
浸漬試験メモリ リークとメモリ劣化を検出する2~8時間持続通常負荷

k6 による負荷テスト

基本的な負荷テスト

// k6/load-test.js
import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  stages: [
    { duration: '2m', target: 50 },   // Ramp up to 50 users
    { duration: '5m', target: 50 },   // Stay at 50 users
    { duration: '2m', target: 100 },  // Ramp up to 100 users
    { duration: '5m', target: 100 },  // Stay at 100 users
    { duration: '2m', target: 0 },    // Ramp down
  ],
  thresholds: {
    http_req_duration: ['p(95)<500', 'p(99)<1000'],
    http_req_failed: ['rate<0.01'],
    http_reqs: ['rate>100'],
  },
};

export default function () {
  // Simulate realistic user behavior
  const homeResponse = http.get('https://example.com/');
  check(homeResponse, {
    'homepage status is 200': (r) => r.status === 200,
    'homepage loads in under 1s': (r) => r.timings.duration < 1000,
  });
  sleep(Math.random() * 3 + 1); // 1-4 seconds think time

  const productsResponse = http.get('https://example.com/api/v1/products');
  check(productsResponse, {
    'products API is 200': (r) => r.status === 200,
    'products API under 500ms': (r) => r.timings.duration < 500,
  });
  sleep(Math.random() * 2 + 1);
}

eコマース ユーザー ジャーニー テスト

// k6/ecommerce-journey.js
import http from 'k6/http';
import { check, group, sleep } from 'k6';

export const options = {
  scenarios: {
    browsing: {
      executor: 'ramping-vus',
      startVUs: 0,
      stages: [
        { duration: '5m', target: 200 },
        { duration: '10m', target: 200 },
        { duration: '5m', target: 0 },
      ],
      exec: 'browsingScenario',
    },
    purchasing: {
      executor: 'ramping-vus',
      startVUs: 0,
      stages: [
        { duration: '5m', target: 20 },
        { duration: '10m', target: 20 },
        { duration: '5m', target: 0 },
      ],
      exec: 'purchaseScenario',
    },
  },
  thresholds: {
    'http_req_duration{scenario:browsing}': ['p(95)<800'],
    'http_req_duration{scenario:purchasing}': ['p(95)<2000'],
    http_req_failed: ['rate<0.01'],
  },
};

export function browsingScenario() {
  group('Browse Products', () => {
    http.get('https://store.example.com/');
    sleep(2);
    http.get('https://store.example.com/products');
    sleep(3);
    http.get('https://store.example.com/products/sample-product');
    sleep(2);
  });
}

export function purchaseScenario() {
  group('Purchase Flow', () => {
    // Browse
    http.get('https://store.example.com/products/sample-product');
    sleep(1);

    // Add to cart
    http.post('https://store.example.com/api/cart', JSON.stringify({
      productId: 'prod_123',
      quantity: 1,
    }), { headers: { 'Content-Type': 'application/json' } });
    sleep(2);

    // Checkout
    http.get('https://store.example.com/cart');
    sleep(3);

    // Place order (simulated)
    const orderResponse = http.post('https://store.example.com/api/checkout/validate', JSON.stringify({
      email: `test-${__VU}@example.com`,
    }), { headers: { 'Content-Type': 'application/json' } });

    check(orderResponse, {
      'checkout validates': (r) => r.status === 200 || r.status === 201,
    });
    sleep(1);
  });
}

ストレス テスト (限界点を見つける)

// k6/stress-test.js
import http from 'k6/http';
import { check } from 'k6';

export const options = {
  stages: [
    { duration: '2m', target: 100 },
    { duration: '5m', target: 100 },
    { duration: '2m', target: 200 },
    { duration: '5m', target: 200 },
    { duration: '2m', target: 500 },
    { duration: '5m', target: 500 },
    { duration: '2m', target: 1000 },
    { duration: '5m', target: 1000 },
    { duration: '5m', target: 0 },
  ],
};

export default function () {
  const res = http.get('https://example.com/api/v1/products');
  check(res, {
    'status is 200': (r) => r.status === 200,
  });
}

結果の解釈

主要な指標

メトリック健康警告クリティカル
P95 応答時間<500ms500ms-2s>2秒
P99 応答時間<1秒1-5秒>5秒
エラー率<0.1%0.1-1%>1%
スループット目標を達成目標の 80%目標の 80% 未満

一般的なボトルネック パターン

CPU バウンドのボトルネック: 応答時間は負荷に応じて直線的に増加します。 P95 と P99 はゆっくりと発散します。

  • 修正: ホット コード パスの最適化、CPU 容量の追加、または水平方向のスケーリング

データベースのボトルネック: 応答時間は、特定の負荷しきい値で指数関数的に増加します。接続プールが枯渇しました。

メモリのボトルネック: 時間の経過とともに徐々に劣化します。 GC の一時停止により、レイテンシのスパイクが発生します。

  • 修正: メモリを増やし、メモリ リークを修正し、オブジェクト割り当てを最適化します。

ネットワークのボトルネック: 応答時間はすべてのエンドポイントで均一に増加します。帯域幅の飽和。

  • 修正: 静的アセットの CDN、圧縮、ペイロード サイズの削減

パフォーマンスのベースライン

ベースラインの確立

最適化する前に、現在のパフォーマンスを文書化します。

# Run baseline test
k6 run --out json=baseline-results.json k6/load-test.js

# Compare after optimization
k6 run --out json=optimized-results.json k6/load-test.js

パフォーマンス予算

各エンドポイントの許容可能なパフォーマンスを定義します。

エンドポイントP95 ターゲットスループット目標
ホームページ500ミリ秒200 リクエスト/秒
製品一覧800ミリ秒150 リクエスト/秒
製品詳細600ミリ秒200 リクエスト/秒
カートに追加300ミリ秒100 リクエスト/秒
チェックアウト2000ミリ秒50 リクエスト/秒
検索500ミリ秒100 リクエスト/秒
管理者ダッシュボード1500ミリ秒20 リクエスト/秒

CI/CD の統合

自動パフォーマンス回帰テスト

# .github/workflows/performance.yml
name: Performance Test
on:
  push:
    branches: [main]

jobs:
  load-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Run k6 load test
        uses: grafana/k6-action@v0.3.1
        with:
          filename: k6/load-test.js
          flags: --out json=results.json
        env:
          K6_TARGET_URL: ${{ secrets.STAGING_URL }}

      - name: Check thresholds
        run: |
          if grep -q '"thresholds":{".*":"fail"' results.json; then
            echo "Performance thresholds exceeded!"
            exit 1
          fi

負荷テストのチェックリスト

テストの前に

  • 環境は本番環境と一致します (インスタンス タイプ、データベース サイズ)。
  • テスト データは代表的なものです (現実的な製品数、ユーザー数)。
  • モニタリングがアクティブです (テスト中にサーバーのメトリクスを追跡します)
  • 関係者に通知されます (負荷テストによりアラートがトリガーされる可能性があります)
  • CDN とキャッシュは運用環境と同じように構成されています

テスト中

  • サーバーの CPU、メモリ、ディスク I/O を監視します
  • データベース接続とクエリ遅延を監視します。
  • エラー率の増加に注意してください
  • リソースの枯渇をチェックします (ファイル記述子、接続)
  • パフォーマンスが低下する負荷レベルに注意してください

テスト後

  • ベースライン結果を文書化する
  • ボトルネックとその負荷しきい値を特定します
  • パフォーマンス向上のためのチケットを作成する
  • パフォーマンス バジェットと比較する
  • 最適化後のフォローアップ テストをスケジュールする

よくある質問

テストの本番環境またはステージングをロードする必要がありますか?

できれば両方。定期的なテストと CI/CD 統合のためのステージング。ステージングではデータベース サイズ、キャッシュ ウォーム、CDN 構成、およびネットワーク トポロジが異なることが多いため、定期的な検証 (トラフィックの少ない時間帯) のための運用。 1 つの環境しかテストできない場合は、ステージングをテストしますが、できる限り実稼働環境に近づけてください。

負荷テストはどれくらいの頻度で実行する必要がありますか?

すべてのデプロイメントでスモーク テストを実行します (CI/CD で自動化)。全負荷テストは毎週、またはメジャー リリース前に行われます。ストレス テストは四半期ごと、または既知のトラフィックの多いイベント (販売、発売) の前に実施します。ソーク テストを四半期ごとに実施して、メモリ リークと長期的な劣化を検出します。

ERP システムの負荷テストはどのように行うのでしょうか?

ERP 負荷テストでは、請求書の生成、注文書の作成、レポートの実行、データのインポートなど、さまざまなタスクを実行する同時ユーザーをシミュレートする必要があります。最も負荷の高い操作 (レポート生成、データ インポート) と最も同時実行される操作 (ピーク時の注文入力) に焦点を当てます。 ECOSIRE は、サポート サービスの一環として Odoo パフォーマンス テスト を提供します。

リクエスト間の現実的な思考時間はどれくらいですか?

e コマースのブラウジングの場合: 2 ~ 5 秒。フォーム入力の場合: 10 ~ 30 秒。チェックアウトの場合: 15 ~ 60 秒。管理者/ERP 使用の場合: 5 ~ 15 秒。負荷テストには常にランダム化された思考時間を追加してください。一定の間隔では、非現実的な同期負荷パターンが作成されます。


次に何が起こるか

負荷テストにより、最適化の取り組みの指針となるボトルネックが明らかになります。データベースのボトルネックについては データベース スケーリング、静的アセット配信については CDN 最適化、エラスティック キャパシティについては 自動スケーリング をフォローアップします。

パフォーマンスのテストと最適化については ECOSIRE にお問い合わせ、完全なインフラストラクチャ戦略については DevOps ガイド をご覧ください。


ECOSIRE が発行 -- 企業がプレッシャーの下でもパフォーマンスを発揮するアプリケーションを構築できるように支援します。

E

執筆者

ECOSIRE Team

テクニカルライティング

ECOSIRE のテクニカルライティングチームは、Odoo ERP、Shopify による EC、AI エージェント、Power BI による分析、GoHighLevel による自動化、そしてエンタープライズソフトウェアのベストプラクティスを扱っています。私たちのガイドは、企業が十分な情報に基づいてテクノロジーを判断できるよう支援します。

ECOSIRE

ECOSIRE でビジネスを成長させましょう

ERP、eコマース、AI、分析、自動化にわたるエンタープライズ ソリューション。

パフォーマンスとスケーラビリティのその他の記事

Webhook のデバッグと監視: 完全なトラブルシューティング ガイド

障害パターン、デバッグ ツール、再試行戦略、監視ダッシュボード、セキュリティのベスト プラクティスを網羅したこの完全なガイドを利用して、Webhook デバッグをマスターしてください。

k6 負荷テスト: 起動前に API のストレス テストを行う

Node.js API の k6 負荷テストをマスターします。仮想ユーザーの増加、しきい値、シナリオ、HTTP/2、WebSocket テスト、Grafana ダッシュボード、CI 統合パターンをカバーします。

Nginx 実稼働構成: SSL、キャッシュ、およびセキュリティ

Nginx 実稼働構成ガイド: SSL 終端、HTTP/2、キャッシュヘッダー、セキュリティヘッダー、レート制限、リバースプロキシセットアップ、Cloudflare 統合パターン。

Odoo パフォーマンス チューニング: PostgreSQL とサーバーの最適化

Odoo 19 のパフォーマンス チューニングに関する専門ガイド。 PostgreSQL の構成、インデックス作成、クエリの最適化、Nginx キャッシュ、エンタープライズ展開のためのサーバーのサイジングについて説明します。

本番環境での AI エージェントのテストと監視

実稼働環境で AI エージェントをテストおよび監視するための完全なガイド。 OpenClaw 導入の評価フレームワーク、可観測性、ドリフト検出、インシデント対応について説明します。

OpenClaw を使用したコンプライアンス監視エージェント

継続的なコンプライアンス監視のために OpenClaw AI エージェントを導入します。規制チェック、ポリシーの適用、監査証跡の生成、コンプライアンスレポートを自動化します。