パフォーマンステストの種類
- 負荷テスト: 想定される負荷での動作確認
- ストレステスト: 限界を超えた負荷での動作確認
- スパイクテスト: 急激な負荷増加への対応確認
- 耐久テスト: 長時間の負荷での安定性確認
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
重要な指標
| 指標 | 説明 | 目標値の例 |
|---|---|---|
| Throughput | 1秒あたりのリクエスト数 | ビジネス要件による |
| 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' }));
}
関連記事
- パフォーマンス最適化 - 最適化手法
- ログ集約と分析 - 監視
- CI/CDパイプライン - 自動化
まとめ
パフォーマンステストは、システムの信頼性を確保するために不可欠です。k6やArtilleryを使って定期的にテストを実施し、CI/CDパイプラインに組み込みましょう。
← 一覧に戻る