performance-testing について
性能テストの計画と実施を支援するスキルです。SLO、現実的な負荷シナリオ、監視、ボトルネック分析に加え、テスト種別の選択やベースライン比較も扱います。
主な機能
- 01応答時間・スループット・エラー率の SLO 定義
- 02負荷・ストレス・スパイク・耐久テストの計画
- 03ユーザー行動と重要な処理経路のモデル化
- 04リソース監視とボトルネック分析
- 05性能ベースラインとの変化追跡
活用シーン
- 01リリース前の想定トラフィック検証
- 02インフラ変更後のスケーリング評価
- 03急なトラフィック増加への備え
- 04テスト結果の比較と性能劣化の調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ proffesor-for-testing/ agentic-qe --skill performance-testingインストール後、Claude Code で/performance-testingを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
config.jsonrun-history.jsonevals/performance-testing.yamlreferences/k6-patterns.mdschemas/output.jsonscripts/validate-config.json詳細
パフォーマンステスト
<default_to_action> パフォーマンスをテストする場合、または負荷テストを計画する場合:
- SLO を定義します:p95 応答時間、スループット、エラー率の目標
- 重要なパスを特定します:収益につながるフロー、トラフィックの多いページ、主要な API
- 現実的なシナリオを作成します:ユーザージャーニー、思考時間、さまざまなデータ
- モニタリングしながら実行します:CPU、メモリ、DB クエリ、ネットワーク
- ボトルネックを分析し、本番環境に導入する前に修正します
テストタイプのクイック選択:
- 想定負荷の検証 → 負荷テスト
- 限界点の特定 → ストレステスト
- 突発的なトラフィック急増 → スパイクテスト
- メモリリーク、リソース枯渇 → 耐久/ソークテスト
- 水平/垂直スケーリング → スケーラビリティテスト
成功のための重要な要素:
- パフォーマンスは後回しにせず、機能の一部として扱います
- リリース直前だけでなく、早い段階から頻繁にテストします
- ユーザーに影響するボトルネックに注力します </default_to_action>
クイックリファレンスカード
使用するタイミング
- 主要リリースの前
- インフラストラクチャの変更後
- スケーリングイベント(Black Friday)の前
- SLA/SLO の設定時
テストタイプ
| タイプ | 目的 | タイミング |
|---|---|---|
| 負荷 | 想定されるトラフィック | リリースごと |
| ストレス | 容量を超える負荷 | 四半期ごと |
| スパイク | 突発的な急増 | イベントの前 |
| 耐久 | メモリリーク | コード変更後 |
| スケーラビリティ | スケーリングの検証 | インフラストラクチャの変更時 |
主要なメトリクス
| メトリクス | 目標 | 理由 |
|---|---|---|
| p95 応答時間 | < 200ms | ユーザーエクスペリエンス |
| スループット | 10k req/min | 容量 |
| エラー率 | < 0.1% | 信頼性 |
| CPU | < 70% | 余裕 |
| メモリ | < 80% | 安定性 |
ツール
- k6:モダンで、JS ベース、CI/CD に適しています
- JMeter:エンタープライズ向けで、機能が豊富です
- Artillery:シンプルな YAML 設定
- Gatling:Scala を使用し、レポート機能に優れています
エージェントの連携
qe-performance-tester:負荷テストのオーケストレーションqe-quality-analyzer:結果の分析qe-production-intelligence:本番環境との比較
SLO の定義
悪い例:「システムは高速であるべき」 良い例:「1,000 人の同時ユーザーがいる状況で、p95 応答時間が 200ms 未満」
export const options = {
thresholds: {
http_req_duration: ['p(95)<200'], // 95% < 200ms
http_req_failed: ['rate<0.01'], // < 1% failures
},
};
現実的なシナリオ
**悪い例:**すべてのユーザーがホームページに繰り返しアクセスする **良い例:**実際のユーザー行動をモデル化する
// Realistic distribution
// 40% browse, 30% search, 20% details, 10% checkout
export default function () {
const action = Math.random();
if (action < 0.4) browse();
else if (action < 0.7) search();
else if (action < 0.9) viewProduct();
else checkout();
sleep(randomInt(1, 5)); // Think time
}
よくあるボトルネック
データベース
**症状:**負荷時のクエリが遅い、コネクションプールの枯渇 **対策:**インデックスの追加、N+1 クエリの最適化、プールサイズの拡大、リードレプリカの使用
N+1 クエリ
// BAD: 100 orders = 101 queries
const orders = await Order.findAll();
for (const order of orders) {
const customer = await Customer.findById(order.customerId);
}
// GOOD: 1 query
const orders = await Order.findAll({ include: [Customer] });
同期処理
**問題:**リクエスト処理中のブロッキング操作(チェックアウト中のメール送信など) **対策:**メッセージキューを使用し、非同期に処理して、すぐに応答を返します
メモリリーク
**検出:**耐久テスト、メモリプロファイリング **よくある原因:**イベントリスナーのクリーンアップ漏れ、追い出し処理のないキャッシュ
外部依存関係
**対策:**短いタイムアウト、サーキットブレーカー、キャッシュ、グレースフルデグラデーション
k6 CI/CD の例
// performance-test.js
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
stages: [
{ duration: '1m', target: 50 }, // Ramp up
{ duration: '3m', target: 50 }, // Steady
{ duration: '1m', target: 0 }, // Ramp down
],
thresholds: {
http_req_duration: ['p(95)<200'],
http_req_failed: ['rate<0.01'],
},
};
export default function () {
const res = http.get('https://api.example.com/products');
check(res, {
'status is 200': (r) => r.status === 200,
'response time < 200ms': (r) => r.timings.duration < 200,
});
sleep(1);
}
# GitHub Actions
- name: Run k6 test
uses: grafana/[email protected]
with:
filename: performance-test.js
結果の分析
良好な結果
Load: 1,000 users | p95: 180ms | Throughput: 5,000 req/s
Error rate: 0.05% | CPU: 65% | Memory: 70%
問題
Load: 1,000 users | p95: 3,500ms ❌ | Throughput: 500 req/s ❌
Error rate: 5% ❌ | CPU: 95% ❌ | Memory: 90% ❌
根本原因の分析
- メトリクスを関連付けます:応答時間が急増したとき、何が変化していますか?
- ログを確認します:エラー、警告、遅いクエリ
- コードをプロファイリングします:どこで時間がかかっていますか?
- リソースをモニタリングします:CPU、メモリ、ディスク
- リクエストをトレースします:エンドツーエンドのフロー
アンチパターン
| ❌ アンチパターン | ✅ より良い方法 |
|---|---|
| テストが遅すぎる | 早い段階から頻繁にテストする |
| 非現実的なシナリオ | 実際のユーザー行動をモデル化する |
| 0 人から 1000 人へ瞬時に増やす | 段階的に負荷を増やす |
| テスト中にモニタリングしない | すべてをモニタリングする |
| ベースラインがない | 傾向を把握し、追跡する |
| 一度きりのテスト | 継続的なパフォーマンステスト |
エージェント支援によるパフォーマンステスト
// Comprehensive load test
await Task("Load Test", {
target: 'https://api.example.com',
scenarios: {
checkout: { vus: 100, duration: '5m' },
search: { vus: 200, duration: '5m' },
browse: { vus: 500, duration: '5m' }
},
thresholds: {
'http_req_duration': ['p(95)<200'],
'http_req_failed': ['rate<0.01']
}
}, "qe-performance-tester");
// Bottleneck analysis
await Task("Analyze Bottlenecks", {
testResults: perfTest,
metrics: ['cpu', 'memory', 'db_queries', 'network']
}, "qe-performance-tester");
// CI integration
await Task("CI Performance Gate", {
mode: 'smoke',
duration: '1m',
vus: 10,
failOn: { 'p95_response_time': 300, 'error_rate': 0.01 }
}, "qe-performance-tester");
エージェント連携のヒント
メモリの名前空間
aqe/performance/
├── results/* - Test execution results
├── baselines/* - Performance baselines
├── bottlenecks/* - Identified bottlenecks
└── trends/* - Historical trends
フリート連携
const perfFleet = await FleetManager.coordinate({
strategy: 'performance-testing',
agents: [
'qe-performance-tester',
'qe-quality-analyzer',
'qe-production-intelligence',
'qe-deployment-readiness'
],
topology: 'sequential'
});
本番前チェックリスト
- 負荷テストに合格(想定トラフィック)
- ストレステストに合格(想定の2~3倍)
- スパイクテストに合格(急激な増加)
- 耐久テストに合格(24時間以上)
- データベースのインデックスを設定
- キャッシュを設定
- モニタリングとアラートを設定
- パフォーマンスのベースラインを確立
関連スキル
- agentic-quality-engineering - エージェントの連携
- api-testing-patterns - API パフォーマンス
- chaos-engineering-resilience - レジリエンスのテスト
覚えておくこと
パフォーマンスは機能です: 機能と同じようにテストしてください 継続的にテスト: リリース前だけではありません 本番環境を監視: 合成モニタリングと実ユーザーモニタリングを併用します 重要な問題を修正: ユーザーに影響するボトルネックに注力します 時間の経過を追跡: 劣化を早期に検出します
エージェントを活用: エージェントは負荷テストを自動化し、ボトルネックを分析して、本番環境と比較します。エージェントを活用して、大規模な環境でもパフォーマンスを維持します。
実行履歴
パフォーマンステストを実行するたびに、このスキルのディレクトリにある run-history.json に結果を追記します。
node -e "
const fs = require('fs');
const h = JSON.parse(fs.readFileSync('.claude/skills/performance-testing/run-history.json'));
h.runs.push({date: new Date().toISOString().split('T')[0], scenario: 'load', p95_ms: P95, throughput_rps: RPS, error_rate_pct: ERR});
fs.writeFileSync('.claude/skills/performance-testing/run-history.json', JSON.stringify(h, null, 2));
"
各実行の前に run-history.json を読み込み、ベースラインと比較します。p95 がベースラインから20%を超えて増加した場合はアラートを出します。
注意点
- エージェントが生成した k6 スクリプトでは、ベース URL がハードコードされることがよくあります。移植性を確保するため、環境変数を使用してください
- コンテナ内での負荷テストでは、アプリケーションの限界より先にリソース制限に達します。コンテナに対象の2倍のリソースがあることを確認してください
- エージェントがリクエスト間の思考時間を含め忘れることがあります。これがないと、負荷が非現実的に集中します
- P95 と P99 の違いは重要です。エージェントは平均値をデフォルトで使用し、テールレイテンシの問題を見えにくくします
- ベースラインとの比較には一貫した環境が必要です。CI ランナーのばらつきによって、20%以上のノイズが発生することがあります