EXERCISE 90分

ストーリー

金曜日の17、あなたのスマートフォンにPagerDutyアラートが届いた。

[SEV2] EC Site - Order Error Rate > 5% (持続10分)

高橋アーキテクトは不在。あなたがインシデントコマンダーとして対応しなければならない。

ログ、メトリクス、トレースを駆使して、原因を特定し、サービスを復旧させろ。

これがMonth 7の集大成だ。すべての知識を総動員して挑め。


演習の概要

本番障害のシナリオに基づいて、オブザーバビリティデータを分析し、根本原因の特定から復旧、ポストモーテムまでを実施してください。

システム構成(再掲)

[Client] → [API Gateway] → [Auth Service]
                          → [Order Service] → [Inventory Service]
                          → [Payment Service] → [Stripe API]
                          → [Notification Service] → [Email API]

ミッション一覧

#ミッション配点
1インシデント初動対応15点
2メトリクスによる影響範囲の把握15点
3トレースによるボトルネック特定20点
4ログによる根本原因の特定20点
5復旧対応と改善提案15点
6ポストモーテムの作成15点

シナリオ情報

障害の状況

17

- PagerDutyアラート発火

Alert: Order Service Error Rate > 5%
Current: 12.3%
Duration: 10 minutes
Dashboard: https://grafana.example.com/d/order-service

メトリクスデータ

Time    | Order RPS | Error Rate | P99 Latency | Payment RPS | Payment Err%
16:40   | 450       | 0.2%       | 320ms       | 200         | 0.1%
16:45   | 455       | 0.3%       | 310ms       | 202         | 0.2%
16:50   | 460       | 0.2%       | 340ms       | 198         | 0.1%
16:55   | 448       | 8.5%       | 4200ms      | 196         | 15.2%   ← 異常開始
17:00   | 380       | 12.3%      | 8500ms      | 160         | 22.1%
17:05   | 320       | 18.5%      | timeout     | 120         | 35.0%

トレースデータ(遅いリクエストの例)

Trace ID: trace-abc-789 (Total: 12,500ms - TIMEOUT)

[API Gateway]     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━  12,500ms
  ├─[Auth Service] ━━  25ms (OK)
  └─[Order Service] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━  12,400ms
      ├─[DB: get order] ━━  8ms (OK)
      ├─[Inventory Svc] ━━━━  35ms (OK)
      └─[Payment Service] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━  12,300ms (ERROR)
          ├─[Validate] ━━  5ms (OK)
          └─[Stripe API] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━  12,250ms (ERROR)
              attributes: {
                http.status_code: 0,
                error.type: "ECONNREFUSED",
                net.peer.name: "api.stripe.com",
                net.peer.port: 443
              }
              events: [
                { name: "connection_attempt", attempt: 1, timestamp: "16:55:01" },
                { name: "connection_failed", error: "ECONNREFUSED", timestamp: "16:55:01" },
                { name: "retry", attempt: 2, timestamp: "16:55:05" },
                { name: "retry", attempt: 3, timestamp: "16:55:09" },
                { name: "all_retries_exhausted", timestamp: "16:55:13" }
              ]

ログデータ

{"timestamp":"16:54:58","level":"INFO","service":"deployment","message":"Deploying payment-service v3.2.0","version":"v3.2.0","previousVersion":"v3.1.5"}

{"timestamp":"16:55:01","level":"ERROR","service":"payment-service","message":"Connection refused to Stripe API","traceId":"trace-abc-789","error":{"code":"ECONNREFUSED","host":"api.stripe.com","port":443}}

{"timestamp":"16:55:05","level":"WARN","service":"payment-service","message":"Retry attempt for Stripe API","traceId":"trace-abc-789","attempt":2,"maxRetries":3}

{"timestamp":"16:55:13","level":"ERROR","service":"payment-service","message":"All retries exhausted for Stripe API","traceId":"trace-abc-789","retriesExhausted":true}

{"timestamp":"16:55:30","level":"ERROR","service":"payment-service","message":"TLS handshake failed","error":{"code":"ERR_TLS_CERT_ALTNAME_INVALID","message":"Hostname/IP does not match certificate's altnames"}}

{"timestamp":"16:56:00","level":"WARN","service":"order-service","message":"Payment timeout, order creation failed","traceId":"trace-def-123","orderId":"ORD-8891","timeout":12000}

ミッション1: インシデント初動対応

アラートを受けてからの初動対応を記述してください。

要件

  • インシデントの分類(SEV判定)
  • コミュニケーションチャネルの開設
  • 関係者への初報
解答例(自分で実装してから確認しよう)
# 初動対応

## SEV判定: SEV2(重大)
- 理由: 注文のエラー率が12%超え、売上に直接影響するが、サービス全停止ではない

## コミュニケーション
1. Slack #incident-20250115-payment を作成
2. 初報を投稿:

[SEV2] EC Site - 注文エラー率上昇
影響: 注文の約12%が失敗中
現状: 調査中
担当: [自分の名前](インシデントコマンダー)
チャネル: #incident-20250115-payment

3. Payment チームリードにSlack DMで通知
4. 次の更新: 15分後

ミッション2: メトリクスによる影響範囲の把握

メトリクスデータを分析し、影響範囲を特定してください。

要件

  • どのサービスに問題が発生しているか
  • いつから問題が始まったか
  • 影響を受けているユーザーの割合
解答例(自分で実装してから確認しよう)
# メトリクス分析結果

## 問題のあるサービス
- Payment Service: エラー率が16:55頃から急増(0.1% → 15.2% → 35%)
- Order Service: Payment Serviceの影響でエラー率が上昇(0.2% → 18.5%)
- API Gateway: Order Serviceのタイムアウトでレイテンシ増加

## 問題の開始時刻
- 16:54-16:55頃(メトリクスでは16:55の集計で異常検知)

## 影響範囲
- 影響を受けているリクエスト: 決済を伴う全注文(全リクエストの約40%)
- Auth Service, Inventory Service, Notification Service: 正常
- 推定影響ユーザー: 全アクティブユーザーの約35-40%

## デプロイとの相関
- 16:54:58にpayment-service v3.2.0がデプロイされている → 強い相関あり!

ミッション3: トレースによるボトルネック特定

トレースデータを分析し、ボトルネックを特定してください。

解答例(自分で実装してから確認しよう)
# トレース分析結果

## ボトルネック
- Payment Service → Stripe API の呼び出しがECONNREFUSEDで失敗
- 3回のリトライ後にタイムアウト(合計12,250ms)
- エラータイプ: ECONNREFUSED(接続拒否)

## 呼び出しの経路
API Gateway → Order Service → Payment Service → Stripe API
全体の遅延の99%がStripe API呼び出しで発生

## Span属性から読み取れる情報
- http.status_code: 0(レスポンスが返っていない)
- error.type: ECONNREFUSED(接続段階で失敗)
- リトライが3回行われ、すべて失敗

## 追加調査
- TLS handshake failedのログあり → 証明書の問題の可能性
- ERR_TLS_CERT_ALTNAME_INVALID → ホスト名と証明書のaltnames不一致

ミッション4: ログによる根本原因の特定

ログデータを分析し、根本原因を特定してください。

解答例(自分で実装してから確認しよう)
# 根本原因分析

## 時系列の整理
1. 16:54:58 - payment-service v3.2.0 がデプロイされた
2. 16:55:01 - Stripe APIへの接続がECONNREFUSEDで失敗開始
3. 16:55:30 - TLS handshake失敗ログ: ERR_TLS_CERT_ALTNAME_INVALID

## 根本原因
payment-service v3.2.0のデプロイで、Stripe API接続の設定が変更され、
TLS証明書の検証でホスト名不一致エラーが発生している。

## 5 Whys分析
1. なぜ注文が失敗した? → Payment Serviceがエラーを返した
2. なぜPayment Serviceがエラーを返した? → Stripe APIに接続できない
3. なぜStripe APIに接続できない? → TLS handshakeで証明書エラー
4. なぜ証明書エラーが発生した? → v3.2.0でStripe SDKの設定が変更された
5. なぜ本番デプロイ前に気づけなかった? → ステージングのStripe APIがモック

## 根本原因
v3.2.0でのStripe SDK設定変更により、TLS接続のホスト名検証が
api.stripe.comの証明書と不一致になった。ステージング環境では
モックAPIを使用していたため、この問題を検出できなかった。

ミッション5: 復旧対応と改善提案

サービスの復旧手順と再発防止の改善提案を作成してください。

解答例(自分で実装してから確認しよう)
# 復旧対応

## 暫定対応(即座に実施)
1. payment-service を v3.1.5 にロールバック
   $ kubectl rollout undo deployment/payment-service
2. ロールバック後にメトリクスを監視
   - エラー率が0.5%以下に回復することを確認
   - P99レイテンシが500ms以下に回復することを確認
3. 15分間安定していることを確認してインシデントクローズ

## 再発防止策

| 優先度 | 対策 | 担当 | 期限 |
|--------|------|------|------|
| P0 | カナリアリリースの導入(1% → 10% → 50% → 100%) | SREチーム | 2週間 |
| P0 | ステージング環境でStripe Sandbox APIを使用 | Paymentチーム | 1週間 |
| P1 | Payment ServiceのE2Eテスト(Stripe API接続テスト含む)| QAチーム | 3週間 |
| P1 | Stripe SDK更新時の専用チェックリスト作成 | Paymentチーム | 2週間 |
| P2 | サーキットブレーカーの導入(Stripe API障害時のフォールバック)| Paymentチーム | 1ヶ月 |

ミッション6: ポストモーテムの作成

今回のインシデントのポストモーテムを作成してください。

解答例(自分で実装してから確認しよう)
# ポストモーテム: Payment Service v3.2.0 デプロイによる注文障害

## 基本情報
| 項目 | 内容 |
|------|------|
| 日時 | 2025-01-15 16:55 - 17:25 (30分) |
| 重要度 | SEV2 |
| 影響 | 注文の約35%が失敗、推定1200件の注文に影響 |
| 作成者 | [自分の名前] |

## サマリー
payment-service v3.2.0のデプロイに含まれるStripe SDK設定変更により、
Stripe APIへのTLS接続が失敗し、全決済処理がエラーとなった。
v3.1.5へのロールバックにより30分で復旧。

## タイムライン
| 時刻 | イベント |
|------|---------|
| 16:54 | payment-service v3.2.0 デプロイ完了 |
| 16:55 | Stripe API接続エラー開始 |
| 17:00 | PagerDutyアラート発火、インシデント対応開始 |
| 17:05 | ダッシュボードでPayment Serviceのエラー率急増を確認 |
| 17:10 | トレースでStripe API接続エラーを特定 |
| 17:12 | ログでTLS証明書エラーとデプロイの相関を発見 |
| 17:15 | v3.1.5へのロールバックを決定・実行 |
| 17:20 | ロールバック完了、エラー率が減少開始 |
| 17:25 | エラー率正常化を確認、インシデントクローズ |

## 根本原因
v3.2.0でのStripe SDK更新による接続設定の破壊的変更。
ステージング環境がモックAPIを使用していたため検出できず。

## 良かった点
- オブザーバビリティが整備されていたため、15分で根本原因を特定できた
- ロールバック手順が整備されていたため、迅速に復旧できた

## アクションアイテム
| ID | 内容 | 担当 | 優先度 | 期限 |
|----|------|------|--------|------|
| AI-1 | カナリアリリースの導入 | SRE | P0 | 1/31 |
| AI-2 | ステージングでStripe Sandbox使用 | Payment | P0 | 1/22 |
| AI-3 | Payment E2Eテスト追加 | QA | P1 | 2/7 |
| AI-4 | サーキットブレーカー導入 | Payment | P2 | 2/15 |

達成度チェック

ミッション内容配点完了
1インシデント初動対応15点[ ]
2メトリクスによる影響範囲の把握15点[ ]
3トレースによるボトルネック特定20点[ ]
4ログによる根本原因の特定20点[ ]
5復旧対応と改善提案15点[ ]
6ポストモーテムの作成15点[ ]

まとめ

この総合演習では、Month 7で学んだすべての知識を統合して活用しました。

スキル活用場面
オブザーバビリティの概念3本柱を使い分けた障害調査
構造化ログログからデプロイ情報とエラー詳細を特定
メトリクス影響範囲と時系列変化の把握
分散トレーシングリクエスト経路でのボトルネック特定
SREインシデント対応フロー、ポストモーテム

チェックリスト

  • インシデントの初動対応を適切に実施できた
  • メトリクス、トレース、ログを組み合わせて根本原因を特定できた
  • 暫定対応と再発防止策を提案できた
  • Blamelessなポストモーテムを作成できた

次のステップへ

総合演習が完了したら、最後の卒業クイズに挑戦しましょう。


推定所要時間: 90分