LESSON 40分

ストーリー

佐藤CTO
NexPayは月間10億件のトランザクションを処理する。ピーク時は10,000 TPS。この規模を安定して捌くには、パフォーマンスとスケーラビリティを”設計”として組み込む必要がある

佐藤CTOがモニターにグラフを表示しました。横軸は時間、縦軸はトランザクション数。12時台と18時台に急峻なピークが見えます。

佐藤CTO
さらに、月末の給料日やキャンペーン時には通常の3-5倍のスパイクが来る。年末年始は10倍もありえる。これに耐えるスケーラビリティをどう設計するか?
あなた
Month 2のスケーラブルシステム設計とMonth 8のパフォーマンスエンジニアリングを統合して設計します
佐藤CTO
よし。“理論を知っている”から”設計に落とせる”に進化しよう

多層キャッシュ戦略

NexPayのキャッシュレイヤー

キャッシュ階層:

[クライアント] ─── CDN Cache ─── API Gateway Cache ─── App Cache ─── DB
                    │                   │                  │
                ┌───┴────┐         ┌────┴─────┐      ┌────┴─────┐
                │ 静的    │         │ 認証     │      │ Redis    │
                │ アセット │         │ トークン  │      │ Cluster  │
                │ 1日     │         │ 検証結果  │      │          │
                └────────┘         │ 5分      │      │ ・残高   │
                                   └──────────┘      │   30秒   │
                                                      │ ・為替   │
                                                      │   10秒   │
                                                      │ ・店舗   │
                                                      │   5分    │
                                                      └──────────┘

キャッシュ設計の詳細

データ種別キャッシュ層TTL更新戦略整合性要件
静的アセットCloudFront CDN24時間バージョニング結果整合性
APIレスポンス(公開)API Gateway60秒TTLベース結果整合性
認証トークン検証API Gateway5分TTLベース結果整合性
ユーザー残高Redis30秒Write-Through結果整合性(注意)
為替レートRedis10秒TTLベース結果整合性
加盟店情報Redis5分Cache-Aside結果整合性
取引履歴Redis2分Cache-Aside結果整合性
セッションRedis15分Write-Through強整合性

残高キャッシュの注意事項

// 残高キャッシュの設計(整合性を考慮)
interface BalanceCacheDesign {
  // 方針: 残高の「表示用」はキャッシュ、「決済用」はDB直接参照
  strategy: {
    // 残高照会API(表示用): キャッシュ許容
    balanceInquiry: {
      source: "Redis Cache (TTL: 30s)";
      consistency: "結果整合性";
      note: "最大30秒の遅延を許容。UI上に'数十秒の遅延あり'と表示";
    };

    // 決済処理(引落し用): キャッシュ不可
    paymentDebit: {
      source: "Aurora DB (SELECT FOR UPDATE)";
      consistency: "強整合性";
      note: "残高不足の誤判定を防ぐため、必ずDBから最新値を取得";
    };
  };

  // キャッシュ更新フロー
  updateFlow: {
    onPayment: "決済完了 → DB更新 → Redisキャッシュ無効化 → 次回照会時にDBから取得";
    onTransfer: "送金完了 → DB更新 → 送金元・送金先の両方のキャッシュを無効化";
  };
}

コネクションプーリング

データベース接続の最適化

# NexPayコネクションプール設計
connection_pooling:
  # サービス側プーリング(HikariCP / node-pg-pool)
  application_pool:
    payment_service:
      min_connections: 10
      max_connections: 50
      idle_timeout: "30s"
      connection_timeout: "3s"
      validation_query: "SELECT 1"

    account_service:
      min_connections: 20
      max_connections: 100    # 残高照会が多いため大きめ
      idle_timeout: "30s"
      connection_timeout: "3s"

  # RDS Proxy(接続の多重化)
  rds_proxy:
    enabled: true
    purpose: "Lambda/短命Pod/大量Podからの接続を集約"
    max_connections_percent: 80   # DBの最大接続数の80%まで
    idle_client_timeout: "30m"

    # RDS Proxyを使う理由
    benefits:
      - "接続のプーリングとシェアリング"
      - "フェイルオーバー時の自動接続切替"
      - "IAM認証による接続管理"

  # Aurora接続上限の設計
  aurora:
    writer:
      instance_class: "db.r6g.2xlarge"
      max_connections: 2000
      reserved_for_admin: 50
      available_for_apps: 1950

    reader:
      instance_count: 3
      max_connections_per_reader: 2000
      read_routing: "ラウンドロビン(RDS Proxy経由)"

オートスケーリング設計

スケーリング戦略

NexPayオートスケーリング:

                        ┌─────────────────────────────┐
                        │  Predictive Scaling          │
                        │  (予測ベース: 過去データから   │
                        │   ピーク時間帯を予測)         │
                        └──────────┬──────────────────┘

     ┌─────────────────────────────┼─────────────────────────────┐
     │                             │                             │
     ▼                             ▼                             ▼
┌──────────────┐          ┌──────────────┐          ┌──────────────┐
│ Payment Svc  │          │ Account Svc  │          │ Transfer Svc │
│              │          │              │          │              │
│ Min: 6 Pods  │          │ Min: 4 Pods  │          │ Min: 3 Pods  │
│ Max: 60 Pods │          │ Max: 40 Pods │          │ Max: 30 Pods │
│              │          │              │          │              │
│ CPU: 60%     │          │ CPU: 65%     │          │ CPU: 60%     │
│ RPS: 1500/pod│          │ RPS: 2000/pod│          │ RPS: 1000/pod│
└──────────────┘          └──────────────┘          └──────────────┘

HPAとKEDAの使い分け

# Payment Service HPA設定
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: payment-service-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: payment-service
  minReplicas: 6
  maxReplicas: 60
  metrics:
    # CPU使用率ベース
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 60
    # カスタムメトリクス(RPS)ベース
    - type: Pods
      pods:
        metric:
          name: http_requests_per_second
        target:
          type: AverageValue
          averageValue: "1500"
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 30    # 30秒で判断
      policies:
        - type: Percent
          value: 100                     # 一度に100%増加可能
          periodSeconds: 30
    scaleDown:
      stabilizationWindowSeconds: 300   # 5分間安定後に縮小
      policies:
        - type: Percent
          value: 25                      # 一度に25%まで縮小
          periodSeconds: 60

スパイク対応

シナリオ予想倍率対応戦略
ランチタイム(12-13時)2x予測スケーリング(11
給料日(毎月25日前後)3x予測スケーリング + 手動プリウォーム
キャンペーン開始5x事前通知ベースの手動スケールアウト
年末年始10xWarm Pool + 専用のバースト構成
障害回復後のサージ3-5xCircuit Breakerとバックプレッシャーで制御

レイテンシ最適化

レイテンシバジェットの配分

決済API レイテンシバジェット(p99 < 800ms):

┌─────────────────────────────────────────────────────────────┐
│                          800ms                               │
├────────┬──────┬──────────────┬───────┬──────┬──────┬────────┤
│API GW  │Auth  │Risk Check    │Card NW│Account│Notify│Margin │
│ 20ms   │30ms  │  50ms        │300ms  │ 50ms  │30ms  │320ms  │
│        │      │              │ (外部) │      │(非同期)│      │
└────────┴──────┴──────────────┴───────┴──────┴──────┴────────┘

最適化ポイント:
  ①Auth: JWTキャッシュで30ms→5msに短縮
  ②Risk Check: ルールキャッシュで50ms→20msに短縮
  ③Card NW: 外部のため制御不能。タイムアウト500msを設定
  ④Notify: 非同期化で決済クリティカルパスから除外

最適化テクニック一覧

テクニック適用箇所効果
非同期化通知、監査ログ、分析イベントクリティカルパスから除外
並列化リスクチェック + 残高確認直列→並列で待ち時間短縮
プリフェッチ加盟店情報、為替レートリクエスト時の取得を回避
コネクションプーリングDB、Redis、外部API接続確立コストの排除
プロトコル最適化サービス間をgRPCにJSON/REST比で30-50%削減
データ圧縮APIレスポンス(gzip/brotli)転送データ量60-80%削減

負荷テスト戦略

テスト計画

// NexPay負荷テスト設計
interface LoadTestDesign {
  // ツール
  tool: "k6 + Grafana Cloud k6";

  // テストシナリオ
  scenarios: {
    // ベースラインテスト
    baseline: {
      description: "通常トラフィックの再現";
      vus: 1000;
      duration: "30分";
      target: "決済API: p99 < 800ms, エラー率 < 0.05%";
    };

    // ピークテスト
    peak: {
      description: "ランチタイムピークの再現";
      vus: 3000;
      duration: "15分";
      target: "決済API: p99 < 1200ms, エラー率 < 0.1%";
    };

    // スパイクテスト
    spike: {
      description: "キャンペーン開始時の急激な負荷";
      vus: "0 → 5000 (1分間で)";
      duration: "10分";
      target: "スケールアウト完了まで3分以内。エラー率 < 1%";
    };

    // ソークテスト
    soak: {
      description: "長時間の安定性確認";
      vus: 2000;
      duration: "4時間";
      target: "メモリリークなし、レイテンシ劣化なし";
    };

    // ブレイクポイントテスト
    breakpoint: {
      description: "限界値の特定";
      vus: "100 → 10000 (段階的増加)";
      target: "SLO違反が発生するVU数を特定";
    };
  };

  // テスト環境
  environment: {
    type: "本番同等のステージング環境";
    data: "匿名化された本番データのサブセット";
    externalDeps: "モック化(Card Network等)";
  };

  // 定期実行
  schedule: {
    baseline: "毎日(CI/CDパイプライン内)";
    peak: "週次(水曜深夜)";
    spike: "リリース前";
    soak: "月次";
    breakpoint: "四半期";
  };
}

まとめ

ポイント内容
キャッシュ多層キャッシュ戦略。残高は表示用と決済用で分離
コネクションプーリングアプリ層プール + RDS Proxyの2層構成
オートスケーリング予測ベース + メトリクスベースの組み合わせ
レイテンシバジェット配分方式。非同期化と並列化で最適化
負荷テスト5種類のシナリオを定期的に実行。CI/CDに統合

チェックリスト

  • 多層キャッシュ戦略とデータ種別ごとのTTL/更新戦略を理解した
  • 残高キャッシュの整合性に関する注意事項を把握した
  • コネクションプーリングの2層構成(アプリ層 + RDS Proxy)を理解した
  • オートスケーリングのHPA設定とスパイク対応戦略を設計できた
  • レイテンシバジェットの配分方式を理解した
  • 負荷テストの5種類のシナリオと実施スケジュールを把握した

次のステップへ

次は「災害復旧と事業継続設計」に進みます。フィンテックプラットフォームのRPO/RTOとマルチリージョン構成を設計しましょう。


推定読了時間: 40分