パフォーマンステスト実践ガイド

中級 | 30分 read | 2025.01.10

パフォーマンステストの種類

  • 負荷テスト: 想定される負荷での動作確認
  • ストレステスト: 限界を超えた負荷での動作確認
  • スパイクテスト: 急激な負荷増加への対応確認
  • 耐久テスト: 長時間の負荷での安定性確認

k6

インストール

# macOS
brew install k6

# Linux
sudo apt install k6

# Docker
docker run -i grafana/k6 run - <script.js

基本的なテスト

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

export const options = {
  stages: [
    { duration: '30s', target: 20 },   // 30秒で20ユーザーまで増加
    { duration: '1m', target: 20 },    // 1分間20ユーザーを維持
    { duration: '30s', target: 0 },    // 30秒で0ユーザーまで減少
  ],
  thresholds: {
    http_req_duration: ['p(95)<500'],  // 95%のリクエストが500ms以下
    http_req_failed: ['rate<0.01'],    // エラー率1%未満
  },
};

export default function () {
  const res = http.get('https://api.example.com/users');

  check(res, {
    'status is 200': (r) => r.status === 200,
    'response time < 500ms': (r) => r.timings.duration < 500,
  });

  sleep(1);
}

APIテスト

// api-test.js
import http from 'k6/http';
import { check, group } from 'k6';

const BASE_URL = 'https://api.example.com';

export const options = {
  vus: 10,
  duration: '1m',
};

export default function () {
  group('Users API', () => {
    // GET /users
    const listRes = http.get(`${BASE_URL}/users`);
    check(listRes, { 'list users 200': (r) => r.status === 200 });

    // POST /users
    const createRes = http.post(
      `${BASE_URL}/users`,
      JSON.stringify({ name: 'Test User', email: 'test@example.com' }),
      { headers: { 'Content-Type': 'application/json' } }
    );
    check(createRes, { 'create user 201': (r) => r.status === 201 });

    // GET /users/:id
    if (createRes.status === 201) {
      const userId = createRes.json().id;
      const getRes = http.get(`${BASE_URL}/users/${userId}`);
      check(getRes, { 'get user 200': (r) => r.status === 200 });
    }
  });
}

認証付きテスト

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

export function setup() {
  // ログインしてトークン取得
  const loginRes = http.post(
    'https://api.example.com/auth/login',
    JSON.stringify({ email: 'test@example.com', password: 'password' }),
    { headers: { 'Content-Type': 'application/json' } }
  );

  return { token: loginRes.json().token };
}

export default function (data) {
  const params = {
    headers: {
      Authorization: `Bearer ${data.token}`,
      'Content-Type': 'application/json',
    },
  };

  const res = http.get('https://api.example.com/protected', params);
  check(res, { 'authenticated request 200': (r) => r.status === 200 });
}

Artillery

インストール

npm install -g artillery

基本的なテスト

# load-test.yml
config:
  target: "https://api.example.com"
  phases:
    - duration: 60
      arrivalRate: 10
      name: "Warm up"
    - duration: 120
      arrivalRate: 50
      name: "Sustained load"
  defaults:
    headers:
      Content-Type: "application/json"

scenarios:
  - name: "User flow"
    flow:
      - get:
          url: "/users"
          expect:
            - statusCode: 200
      - post:
          url: "/users"
          json:
            name: "Test User"
            email: "test@example.com"
          expect:
            - statusCode: 201
      - think: 1

実行

# テスト実行
artillery run load-test.yml

# レポート出力
artillery run load-test.yml --output report.json
artillery report report.json

Lighthouse (フロントエンド)

# CLIインストール
npm install -g lighthouse

# 実行
lighthouse https://example.com --output html --output-path ./report.html

# CI用
lighthouse https://example.com --output json --chrome-flags="--headless"

Node.jsからの実行

import lighthouse from 'lighthouse';
import * as chromeLauncher from 'chrome-launcher';

async function runLighthouse(url: string) {
  const chrome = await chromeLauncher.launch({ chromeFlags: ['--headless'] });

  const result = await lighthouse(url, {
    port: chrome.port,
    output: 'json',
    onlyCategories: ['performance'],
  });

  await chrome.kill();

  const scores = result.lhr.categories;
  console.log('Performance Score:', scores.performance.score * 100);

  return result;
}

結果の分析

k6メトリクス

http_reqs..................: 15000  250/s
http_req_duration..........: avg=45ms min=10ms med=40ms max=500ms p(90)=80ms p(95)=120ms
http_req_failed............: 0.5%
vus........................: 50

重要な指標

指標説明目標値の例
Throughput1秒あたりのリクエスト数ビジネス要件による
Latency (p95)95パーセンタイルの応答時間< 500ms
Error Rateエラー率< 1%
Availability可用性> 99.9%

CI/CDへの統合

GitHub Actions

# .github/workflows/performance.yml
name: Performance Test

on:
  push:
    branches: [main]

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

      - name: Install k6
        run: |
          sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69
          echo "deb https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6.list
          sudo apt-get update
          sudo apt-get install k6

      - name: Run load test
        run: k6 run --out json=results.json tests/load-test.js

      - name: Check thresholds
        run: |
          if grep -q '"thresholds":{".*":{"ok":false' results.json; then
            echo "Performance thresholds not met"
            exit 1
          fi

ベストプラクティス

1. 本番に近い環境でテスト

# 環境設定
config:
  target: "https://staging.example.com"
  environments:
    staging:
      target: "https://staging.example.com"
    production:
      target: "https://api.example.com"

2. 段階的な負荷増加

export const options = {
  stages: [
    { duration: '2m', target: 10 },   // ウォームアップ
    { duration: '5m', target: 50 },   // 負荷増加
    { duration: '10m', target: 100 }, // ピーク負荷
    { duration: '5m', target: 50 },   // 負荷減少
    { duration: '2m', target: 0 },    // クールダウン
  ],
};

3. リアルなシナリオ

// ユーザーの実際の行動をシミュレート
export default function () {
  // ホームページ閲覧
  http.get(`${BASE_URL}/`);
  sleep(randomIntBetween(1, 3));

  // 商品一覧
  http.get(`${BASE_URL}/products`);
  sleep(randomIntBetween(2, 5));

  // 商品詳細
  http.get(`${BASE_URL}/products/${randomProductId()}`);
  sleep(randomIntBetween(1, 3));

  // カートに追加
  http.post(`${BASE_URL}/cart`, JSON.stringify({ productId: '123' }));
}

関連記事

まとめ

パフォーマンステストは、システムの信頼性を確保するために不可欠です。k6やArtilleryを使って定期的にテストを実施し、CI/CDパイプラインに組み込みましょう。

← Back to list