ストーリー
金曜日の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分