EXERCISE 90分

ストーリー

高橋アーキテクトが最後の課題を出した。

高橋アーキテクト
SpeedShopの大型セールが1ヶ月後に迫っている。現在のシステムは通常時1000 RPSに対応しているが、セール時は10000 RPSが見込まれる。全ての知識を総動員して、10倍の負荷に耐えるシステムを設計し、パフォーマンスを保証するための計画を立ててほしい
高橋アーキテクト
これができたら、君はパフォーマンスエンジニアだ

総合演習の概要

5つのパートで、Month 6の全スキルを実践します。

パートテーマ時間使うスキル
Part 1現状分析と目標設定15分パフォーマンスバジェット、計測
Part 2キャッシュ戦略の設計20分キャッシュ設計、無効化
Part 3スケーリング計画20分水平/垂直スケーリング、非同期処理
Part 4負荷テスト計画20分k6、シナリオ設計
Part 5フロントエンド最適化15分Core Web Vitals、CDN

Part 1: 現状分析と目標設定(15分)

現状のシステム情報

インフラ:
  App Server: 3台(4vCPU, 16GB RAM)
  Database: PostgreSQL 1台(8vCPU, 32GB RAM)+ Read Replica 1台
  Cache: Redis 1台(4GB RAM)
  CDN: なし

パフォーマンス指標(通常時 1000 RPS):
  API p50: 80ms, p95: 200ms, p99: 450ms
  LCP: 3.2秒
  CLS: 0.22
  エラー率: 0.05%
  キャッシュヒット率: 60%
  DB CPU: 45%, App CPU: 35%

ストレステスト結果(2000 RPS時):
  API p50: 250ms, p95: 800ms, p99: 3200ms
  エラー率: 2.5%
  DB CPU: 92%, App CPU: 65%
  Redis メモリ: 85%

課題

セール時10000 RPSに対応するための目標値とギャップを分析してください。

解答例
=== 目標値(SLO) ===
  API p50: 100ms以下
  API p95: 300ms以下
  API p99: 500ms以下
  LCP: 2.5秒以下
  CLS: 0.1以下
  エラー率: 0.1%以下
  キャッシュヒット率: 95%以上

=== ギャップ分析 ===

1. DB がボトルネック
   現状: 1000RPSでCPU 45% → 2000RPSでCPU 92%
   10000RPSでは完全に飽和する
   対策: Read Replica追加 + キャッシュヒット率向上

2. キャッシュヒット率が低い
   現状: 60% → 40%のリクエストがDBに到達
   目標: 95% → 5%のみDBに到達
   対策: TTL見直し + キャッシュ対象の拡大

3. App Server が不足
   現状: 3台で1000RPS → 10000RPSでは最低30台が必要
   対策: オートスケーリング + ステートレス確認

4. Redisメモリ不足
   現状: 1000RPSで85% → キャッシュ増加でOOM
   対策: Redis Cluster化 + メモリ増強

5. CDN未導入
   静的アセットがオリジンから配信されている
   対策: CDN導入で静的アセットのRPSをオフロード

6. フロントエンドのCWV未達
   LCP 3.2秒, CLS 0.22 → 目標未達
   対策: 画像最適化 + width/height指定

Part 2: キャッシュ戦略の設計(20分)

キャッシュヒット率を60%から95%に向上させるための戦略を設計してください。

対象データと現状

データ現状TTLヒット率RPS割合
商品一覧5分70%30%
商品詳細30分80%25%
検索結果なし0%15%
カートなし0%10%
ランキング1時間90%10%
セッション30分95%10%
解答例
// 改善後のキャッシュ設計
const improvedCacheStrategy = {
  // 商品一覧: TTL延長 + イベント無効化
  productList: {
    beforeTTL: 300,       // 5分
    afterTTL: 600,        // 10分に延長
    invalidation: 'event-based', // 商品更新時にイベントで無効化
    expectedHitRate: 90,  // 70% → 90%
  },

  // 商品詳細: 既に良好、微調整
  productDetail: {
    beforeTTL: 1800,
    afterTTL: 1800,       // 維持
    invalidation: 'event-based',
    expectedHitRate: 90,  // 80% → 90%
  },

  // 検索結果: 新規キャッシュ導入
  searchResults: {
    beforeTTL: null,      // キャッシュなし
    afterTTL: 120,        // 2分のキャッシュ導入
    cacheKey: 'search:{query}:{page}:{sort}',
    expectedHitRate: 70,  // 0% → 70%
  },

  // カート: Redisセッション内にキャッシュ
  cart: {
    beforeTTL: null,
    afterTTL: 1800,       // Write-Through
    strategy: 'write-through',
    expectedHitRate: 85,  // 0% → 85%
  },

  // ランキング: 既に良好、維持
  ranking: {
    beforeTTL: 3600,
    afterTTL: 3600,
    expectedHitRate: 95,  // 90% → 95%
  },

  // セッション: 維持
  session: {
    beforeTTL: 1800,
    afterTTL: 1800,
    expectedHitRate: 95,
  },
};

// 全体のキャッシュヒット率の計算
// = Σ(各データのヒット率 × RPS割合)
// = 90*0.30 + 90*0.25 + 70*0.15 + 85*0.10 + 95*0.10 + 95*0.10
// = 27 + 22.5 + 10.5 + 8.5 + 9.5 + 9.5
// = 87.5%

// さらにCDNでの静的アセットキャッシュを考慮すると
// 全体で約92-95%のキャッシュヒット率が期待できる

Thundering Herd対策:

  • セール開始前にランキング・人気商品のキャッシュをウォームアップ
  • Singleflightパターンで同時DB問い合わせを制限
  • TTLにジッター(+0-60秒)を追加して同時期限切れを回避

Part 3: スケーリング計画(20分)

10000 RPSに対応するためのスケーリング計画を策定してください。

解答例
=== インフラスケーリング計画 ===

1. App Server
   現状: 3台(4vCPU)→ 1000 RPS対応
   目標: 最大30台 → 10000 RPS対応
   戦略: オートスケーリング
     - 通常時: 5台
     - セール前日23:00: 20台にスケールアウト(事前スケーリング)
     - セール中: CPU 60%超で+3台、30%以下で-1台
     - 最大: 30台
   前提: ステートレス確認済み(JWT認証 + Redis Session)

2. Database
   現状: Primary 1台 + Replica 1台
   目標: Primary 1台 + Replica 3台 + スペック増強
   戦略:
     - Read Replica: 1台 → 3台(読み取り3倍化)
     - Primary: 8vCPU → 16vCPU(垂直スケーリング)
     - コネクションプール: max=20 → max=100

3. Redis
   現状: 1台(4GB)
   目標: Redis Cluster 3ノード(各8GB = 計24GB)
   戦略:
     - メモリ増強でキャッシュ容量確保
     - クラスタリングで負荷分散

4. CDN
   現状: なし
   目標: CloudFront導入
   効果: 静的アセット(画像、CSS、JS)のRPSをオフロード
         → オリジンへのRPSを50%削減

5. メッセージキュー
   現状: なし
   目標: SQS導入
   対象: メール送信、PDF生成、分析イベント
   Worker: 1-10台(キュー深さに応じてスケーリング)

=== コスト見積もり ===
通常時: $2,000/月(App 5台 + DB 2台 + Redis 1台)
セール時: $8,000/月(App 20台 + DB 4台 + Redis 3台 + CDN + SQS)

Part 4: 負荷テスト計画(20分)

セール前に実施する負荷テストの計画を立ててください。

解答例
=== 負荷テスト実施計画 ===

Phase 1: ベースラインテスト(Day 1)
  種類: ロードテスト
  負荷: 1000 RPS × 10分
  目的: 改善前のベースラインを記録
  環境: ステージング(本番同等構成)

Phase 2: スケーリング確認テスト(Day 7)
  種類: ストレステスト
  負荷: 1000 → 5000 → 10000 → 15000 RPS(段階的)
  目的: 飽和点の特定、オートスケーリングの動作確認
  観察項目:
    - 各段階でのレイテンシ変化
    - オートスケーリングの起動時間
    - DBレプリカの負荷分散状況

Phase 3: セールシミュレーション(Day 14)
  種類: スパイクテスト
  負荷: 1000 RPS → 10000 RPS(1分で急増)→ 10000 RPS維持(30分)→ 1000 RPS
  シナリオ:
    - 閲覧: 60%(商品一覧 + 詳細)
    - 検索: 20%
    - 購入: 20%(セール時は購入比率が高い)
  目的: セール開始時のスパイクに耐えられるか確認

Phase 4: 耐久テスト(Day 21)
  種類: ソークテスト
  負荷: 5000 RPS × 4時間
  目的: メモリリーク、コネクションリーク、Redis OOMの検出

Phase 5: 最終確認テスト(Day 25)
  種類: セールシミュレーション再実行
  目的: 全ての修正が反映された状態での最終確認

=== 合格基準 ===
  p95: 300ms以下
  p99: 500ms以下
  エラー率: 0.1%以下
  スループット: 10000 RPS以上
  オートスケーリング: 5分以内にスケールアウト完了

Part 5: フロントエンド最適化(15分)

セール時のフロントエンドパフォーマンスを確保するための施策をまとめてください。

解答例
=== フロントエンド最適化施策 ===

1. セールページの事前最適化
   - セールバナー画像: AVIF/WebP + preload
   - セールページのHTMLをCDNにプリキャッシュ
   - Critical CSS のインライン化

2. バンドル最適化
   - セールに不要なコンポーネントをLazy Loading化
   - 初期バンドルを300KB以下に維持
   - Service Workerで静的アセットをプリキャッシュ

3. CDN設定
   - セール画像を事前にCDNにプッシュ(オリジンプッシュ)
   - エッジでの画像最適化有効化(リサイズ + フォーマット変換)
   - APIレスポンスの短期キャッシュ(商品情報: 1分)

4. CWV目標の達成
   - LCP: 2.5秒以下(Hero画像のpreload + CDN)
   - INP: 200ms以下(重い処理のWeb Worker化)
   - CLS: 0.1以下(全画像にwidth/height指定済み)

5. 障害時のフォールバック
   - CDN障害: オリジンに直接接続
   - API障害: 静的なキャッシュページを表示
   - 決済障害: エラーメッセージ + リトライボタン

達成度チェック

パートテーマ完了
Part 1現状分析と目標設定[ ]
Part 2キャッシュ戦略[ ]
Part 3スケーリング計画[ ]
Part 4負荷テスト計画[ ]
Part 5フロントエンド最適化[ ]

まとめ

ポイント内容
現状分析データに基づいてボトルネックを特定
キャッシュヒット率60% → 95%で DBへのRPSを大幅削減
スケーリングApp水平 + DB垂直/Read Replica + Redis Cluster
負荷テスト段階的にテスト種類を変えて網羅的に検証
フロントエンドCDN + 画像最適化 + バンドル最適化でCWV達成

チェックリスト

  • 現状のメトリクスからボトルネックを特定できた
  • キャッシュ戦略でヒット率向上の計画を立てられた
  • 10倍のトラフィックに対応するスケーリング計画を策定できた
  • 段階的な負荷テスト計画を立案できた
  • フロントエンドのCWV達成施策を列挙できた

次のステップへ

お疲れさまでした。全ての知識を統合した総合的な設計力が身についたはずです。

最後に、卒業クイズに挑戦しましょう。


推定所要時間: 90分