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

中級 | 30分 で読める | 2025.01.10

公式ドキュメント

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

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

ポイント: テストの目的に応じて適切な種類を選びましょう。まずは負荷テストから始めて、段階的にストレステストやスパイクテストへ進めるのが効果的です。

k6

インストール

# macOS
brew install k6

# Linux
sudo apt install k6

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

基本的なテスト

k6ではstagesで負荷の増減パターンを定義し、thresholdsで合格基準を設定します。

// 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 });
 }
 });
}

実践メモ: APIテストではgroup()で関連するリクエストをグループ化すると、レポートが見やすくなり、どのエンドポイントがボトルネックかを特定しやすくなります。

認証付きテスト

// 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

注意: p95レイテンシとエラー率は最低限監視すべき指標です。平均値だけを見ていると、一部ユーザーの深刻な遅延を見逃してしまいます。

重要な指標

指標説明目標値の例
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

ベストプラクティス

ポイント: ベストプラクティスの核心は「本番に近い環境」「段階的な負荷」「リアルなシナリオ」の3つです

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パイプラインに組み込みましょう。

参考リソース

← 一覧に戻る
PR
PR
PR
PR