PCDBE 合格対策
🔬 SRE DEEP DIVE

事故ケースと教訓 — Incidents & Lessons Learned

実際の現場で発生する技術事故パターンと根本原因 (Root Cause)、再発防止策を サービス別に体系化。試験対策だけでなく 実務で同じ事故を起こさないための事故集。

高頻度 中頻度 想定低頻度・致命的

📑 目次

  1. 1. Cloud SQL の事故ケース
  2. 2. AlloyDB の事故ケース
  3. 3. Spanner の事故ケース
  4. 4. Bigtable の事故ケース
  5. 5. Firestore の事故ケース
  6. 6. Memorystore の事故ケース
  7. 7. DMS の事故ケース
  8. 8. Datastream の事故ケース
  9. 9. 全DB横断の事故パターン

1. Cloud SQL の事故ケース

事故 1.1 — ストレージ枯渇による DB ダウン 高頻度

症状: アプリから「Disk full」エラーが噴出し、DB が書き込み不可。読み取りは可能だが、新規トランザクションは即時失敗。
典型ケース: バイナリログ + 日次バックアップで予想以上にストレージが消費、ストレージ自動増加を無効にしていた。
Root Cause:
再発防止:
  1. Storage auto increase は必ず有効化(縮小は不可だが、ダウンよりはマシ)
  2. アラート閾値を「使用率 + 増加率」の 2 軸で設定(例: 70% & 24h で +10% 増)
  3. 不要な binary log を定期的に整理(ただし PITR 期間内は削除不可)
  4. テーブル毎の容量を information_schema.tables で週次監査

事故 1.2 — メジャーアップグレード後ロールバック不可 高頻度

症状: PostgreSQL 13 → 15 にインプレースアップグレード後、アプリが collation エラーで起動不可。ロールバック手段がなく緊急復旧でダウンタイム拡大。
Root Cause: PostgreSQL はメジャーバージョン間で collation 定義が変わる場合があり、既存インデックスが破損して動かない。
Cloud SQL のインプレースアップグレードは 「成功したらロールバック不可」が公式仕様。
再発防止:
  1. メジャーアップグレードは Blue-Green + DMS で並行構築
  2. テスト環境で REINDEX 必要性を事前確認
  3. アプリの全 SQL クエリを新バージョンで EXPLAIN
  4. 切り戻し用に旧バージョンインスタンスを 1 ヶ月維持

事故 1.3 — Cross-region Replica 昇格後のスプリットブレイン 中頻度

症状: 旧 Primary リージョンが復旧した際、旧 Primary とプロモートした新 Primary の両方に書き込みが入り、データ不整合が発生。
Root Cause: クロスリージョン リードレプリカは 手動 Promote。Promote 後、旧 Primary は自動でレプリカに戻らず孤立。DNS / Load Balancer が旧 IP を引いていた場合、一部トラフィックが旧へ流れる。
再発防止:
  1. Promote 直後に旧 Primary を停止(trafficが入らないよう物理的に遮断)
  2. アプリは 接続文字列を集中管理(Secret Manager / Config Server)
  3. DNS TTL を短く(60秒以下)して切り替えを高速化
  4. 切り戻し計画書を事前に作成し、訓練

事故 1.4 — サーバーレスからの接続枯渇 高頻度

症状: Cloud Run のオートスケールが効くピーク時、Cloud SQL が too many connections エラーで応答不可。
Root Cause: Cloud Run の各インスタンスがそれぞれ DB プールを持ち、合計接続数が max_connections を超過。サーバーレスの特性で瞬時にスケールするため検知が遅い
再発防止:
  1. 外部コネクションプーラー導入(PgBouncer on Cloud Run sidecar、AlloyDB 組み込みプーラー)
  2. Cloud SQL Auth Proxy の --max-connections 上限設定
  3. アプリ側でプールサイズを小さく(インスタンス毎に 5-10)
  4. Memorystore でセッションキャッシュ → DB アクセス頻度削減

事故 1.5 — CMEK 鍵削除によるインスタンス停止 低頻度・致命的

症状: Cloud KMS で「不要だと思った鍵」を削除したところ、その鍵で暗号化された Cloud SQL が即時停止。
Root Cause: CMEK 鍵が無効化/削除されると、Cloud SQL はマウントしている永続ディスクを復号できず、即時停止。鍵の使用状況がアラートになっていなかった。
再発防止:
  1. Cloud KMS の鍵削除は destroy schedule(最低24時間〜30日)で猶予を持つ
  2. 鍵削除前に gcloud kms keys list-revoked + 利用先を必ず確認
  3. 本番用 KMS 鍵は 専用プロジェクト + 限定 IAM で管理
  4. KMS の Cloud Monitoring アラートで「decrypt 操作の急減」を検知

2. AlloyDB の事故ケース

事故 2.1 — Read Pool が Primary より大幅に遅延 中頻度

症状: アプリが「直前に書いたデータが Read Pool で読めない」と苦情。レプリ遅延が数秒〜数十秒に拡大。
Root Cause:
再発防止:
  1. 「直近書き込みを即座に読む」必要があるクエリは 明示的に Primary に投げる(アプリで使い分け)
  2. 大規模 DDL は メンテナンスウィンドウで実施
  3. Read Pool のレプリ遅延 (replication_lag) を Cloud Monitoring でアラート(30秒)
  4. バッチ書き込みは 分割コミット でレプリへの負荷を均す

事故 2.2 — Columnar Engine 有効化後に CPU 高騰 中頻度

症状: Columnar Engine を有効化した直後、Primary のメモリ使用率が急上昇し、OLTP クエリのレイテンシ悪化。
Root Cause: Columnar Engine は列ストアを In-memory で構築するため、メモリを消費する。これが OLTP の buffer pool を圧迫した。
再発防止:
  1. google_columnar_engine.memory_size_in_mb でメモリ上限を明示
  2. 列対象テーブルを Recommended Tables 機能で必要最小限に絞る
  3. Columnar 有効化はRAM に余裕のあるマシンタイプへ変更後に実施
  4. OLTP と分析が両方重要なら Read Pool に Columnar、Primary は無効の分離

事故 2.3 — Secondary Cluster Switchover 時のデータロス 低頻度・致命的

症状: プライマリリージョン障害で Secondary Cluster を Switchover したが、直前数秒の書き込みが失われた。
Root Cause: Secondary Cluster は非同期レプリのため、Primary 障害時に WAL が伝播していない数秒分のデータが消失する可能性がある(RPO > 0)。
再発防止:
  1. 「RPO=0 が必要」なら AlloyDB Secondary ではなく Spanner Multi-region を選定
  2. レプリ遅延を継続監視し、遅延が大きければアプリで「書き込み確認後にレスポンス」を強制
  3. 重要トランザクションは二重書き込み(外部 Kafka / Pub/Sub)で保険

3. Spanner の事故ケース

事故 3.1 — 連番主キーによるホットスポット 高頻度

症状: 移行直後は順調だったが、データ量増加とともにレイテンシが線形に悪化。1 ノード追加しても性能改善せず。
Root Cause: Cloud SQL から移行する際に SERIAL 相当の連番 ID を主キーにした。Spanner では末尾スプリットに書き込みが集中し、ノード追加しても 1 ノードしか働かない。
再発防止:
  1. Spanner 主キーは UUID v4 / hash-prefixed / 反転タイムスタンプのいずれか
  2. 移行前にスキーマレビュー、特に主キー設計を Spanner 公式の Schema design best practices で確認
  3. Key Visualizer (Spanner 版) で書き込み分布を可視化
  4. 連番 ID が業務上必要なら シーケンステーブル + hash プレフィックスで分散

事故 3.2 — Multi-region のクエリレイテンシ予想以上 中頻度

症状: Regional から Multi-region に移行したら、書き込みレイテンシが 40ms → 150ms に増加。
Root Cause: Multi-region は複数リージョンの Paxos voter から quorum を取る必要があり、最寄り 2 voter の応答待ち(地理的に近くないと数十 ms 増加)。
再発防止:
  1. Multi-region は SLA 99.999% が必要なケースのみ。それ以外は Regional
  2. Read-only Replica を地域別に配置して読み取りレイテンシ最小化
  3. Default leader region をユーザー多数の地域に設定
  4. Multi-region 移行前に Regional の Cross-region Backupで代替できるか検討

事故 3.3 — Strong Read で予想以上のレイテンシ 中頻度

症状: Spanner の全クエリで Strong Read を使ったらコストとレイテンシが想定の 2 倍。
Root Cause: Strong Read は常に最新の commit timestamp を取得するため、Paxos quorum の応答を待つ。Stale Read(数秒の遅延許容)の方が低コスト・低レイテンシ。
再発防止:
  1. 強整合が必要なクエリだけ Strong Read
  2. 分析・ダッシュボード用は Stale Read (10秒) で十分
  3. Stale Read は Read-only Replica で処理されコスト削減

4. Bigtable の事故ケース

事故 4.1 — Hot Tablet による全クラスタ性能劣化 高頻度

症状: 朝 9 時のピーク時に Bigtable のレイテンシ p99 が 100ms 超え。Key Visualizer で 1 つの行範囲が真っ赤
Root Cause: 行キーに「センサーID_タイムスタンプ昇順」を使っていた。同センサーの全書き込みが 1 Tablet に集中。
再発防止:
  1. 行キー再設計(hash プレフィックス、reverse timestamp)
  2. 変更不可能な既存テーブルは 別テーブルに移行 + デュアル書き込み
  3. Key Visualizer を週次で確認
  4. 新規スキーマは事前に cbt で書き込みテスト → Key Visualizer 確認

事故 4.2 — マルチクラスタ ルーティングで結果整合エラー 中頻度

症状: 「書いた直後に読めない」事象が発生。ユーザー登録→直後ログインで「ユーザー未存在」エラー。
Root Cause: マルチクラスタ ルーティングは eventual consistency。アプリは別クラスタから読みに行く可能性がある。
再発防止:
  1. 「書いた直後に読む」操作は Single-cluster routing or Row-affinity routing の App Profile を使う
  2. App Profile を業務毎に分離(ログイン用、分析用、バックエンド用)
  3. クライアントで read-your-writes パターンを実装(ローカルキャッシュ)

事故 4.3 — SSD → HDD への変更不可で大規模移行 低頻度・大規模

症状: コスト削減のため SSD クラスタを HDD に変えたかったが、ストレージタイプ変更不可と判明。新クラスタ作成・データ全移行・アプリ切り替えで 3 週間の工数。
再発防止:
  1. クラスタ作成時に SSD/HDD を慎重に選択(変更不可)
  2. 用途別にクラスタ分離(リアルタイム=SSD、アーカイブ=HDD)
  3. 必要に応じてマルチクラスタ + レプリで HDD クラスタに分散

5. Firestore の事故ケース

事故 5.1 — 課金爆発(リアルタイムリスナー過剰) 高頻度

症状: 月 $200 の予算が、1 日で $5,000 を超える請求アラート。
Root Cause: アプリのバグで「ページロード毎にリスナーを張り直し、解除しない」コードが本番投入。各リスナーが大量のドキュメント変更通知を発生させ read オペレーション課金が爆発
再発防止:
  1. Budget Alert を「予算の 50/80/100%」で 3 段設定
  2. 本番デプロイ前に Firestore Emulator で課金見積もり
  3. リスナーは unsubscribe を必ず実装、useEffect cleanup を徹底
  4. クエリ毎の limit() 必須化
  5. Cloud Logging で「read 数 / hour」が異常に増えたらアラート

事故 5.2 — Security Rules 不備で全データ漏洩 低頻度・致命的

症状: Firestore のセキュリティスキャナで「全ドキュメントが匿名ユーザーから読み取り可能」と通知。
Root Cause: 開発初期の allow read, write: if true; を本番に持ち込んだ。
再発防止:
  1. 本番 deploy 前に firebase deploy --only firestore:rules のレビュー必須
  2. Security Rules の単体テスト(@firebase/rules-unit-testing
  3. 「Test mode」での deploy を CI でブロック
  4. Firestore のセキュリティスキャナを継続有効化

事故 5.3 — 500/50/5 ルール違反で書き込み失敗 中頻度

症状: バッチでデータ投入したら、途中から書き込みが失敗。
Root Cause: 新規 Collection への持続的書き込みは 500 ops/sec が初期上限。これを 5 分毎に 50% ずつ増加させる必要がある。
再発防止:
  1. 大量初期投入は 500 ops/sec → 5分後 750 → ... で徐々に増加
  2. 事前に空ドキュメント書き込みでウォームアップ
  3. 書き込み量が大きい場合は Bigtable に変更

6. Memorystore の事故ケース

事故 6.1 — Basic Tier 再起動でセッション全消失 高頻度

症状: Memorystore Basic Tier のメンテナンスで再起動 → 全ユーザーが強制ログアウト、苦情殺到。
Root Cause: Basic Tier は HA なし・永続化なし。再起動でメモリ上のセッションデータが全消失。
再発防止:
  1. 本番セッションストアは Standard Tier 以上(HA + replication)
  2. セッションは Firestore か Cloud SQL に永続化 + Redis にキャッシュ
  3. Basic Tier は「再構築可能なキャッシュ」専用

事故 6.2 — TTL 設定忘れでメモリ満杯 高頻度

症状: Redis が OOM command not allowed エラーで書き込み拒否。
Root Cause: アプリが SET key value だけで EX(TTL)を付けず、データが無限に蓄積。
再発防止:
  1. すべての SET に TTL 必須化(コードレビュー or ラッパー関数)
  2. maxmemory-policyallkeys-lru に設定(古いデータから自動削除)
  3. メモリ使用率 85% でアラート
  4. キー命名規則を統一して用途別 TTL を可視化

事故 6.3 — Big Key による全 Redis 停止 中頻度

症状: 1 キーの値が数十 MB に膨れ上がり、そのキーへのアクセスで Redis 全体が応答停止。
Root Cause: Redis はシングルスレッド。1 つの大きな値の読み取りが全体をブロック
再発防止:
  1. 1 キー = 100KB 以下を原則
  2. 大きいデータは分割キー(user:123:item:0, user:123:item:1...)
  3. SCAN + STRLEN で定期的に big key 検出
  4. 大きいオブジェクトは GCS に逃がして Redis には URL のみ

7. DMS の事故ケース

事故 7.1 — binlog 削除でレプリ中断 高頻度

症状: MySQL → Cloud SQL の DMS Continuous で、ある日突然レプリが失敗。「binlog file not found」エラー。
Root Cause: ソース MySQL の expire_logs_days が 1 日。DMS のレプリ遅延が大きくなった日に、適用前の binlog が削除されてしまった。レプリ復旧不可、初期 Dump からやり直し
再発防止:
  1. expire_logs_daysレプリ遅延の最悪値 + 余裕で設定(最低 7 日)
  2. レプリ遅延を継続監視、遅延 1 時間でアラート
  3. binlog ストレージ容量も監視(保持期間延長でディスク不足を防ぐ)

事故 7.2 — PK 非保有テーブルで UPDATE 同期されず 中頻度

症状: 移行完了後、新 DB と旧 DB のデータ件数は一致するが、内容が異なるレコードが多数。
Root Cause: 一部のテーブルに Primary Key がなく、DMS の CDC では INSERT のみ反映。UPDATE / DELETE が無視されていた。
再発防止:
  1. 移行前に SELECT で全テーブルの PK 有無を監査
  2. PK のないテーブルには サロゲートキーを事前付与(移行前作業)
  3. 移行後にチェックサム比較
  4. DMS のジョブログで「Replication mode: insert only」警告を必ず確認

事故 7.3 — カットオーバー時のデータロス 低頻度・致命的

症状: アプリ書き込み停止が早すぎ、Promote 時にまだ送られていない transaction が旧 DB に残ってロスト。
Root Cause: 残ログ適用完了の確認なしで Promote ボタンを押した。
再発防止:
  1. カットオーバー手順をチェックリスト化(残ログサイズ = 0 を確認、レプリ遅延 < 1秒)
  2. ステージング環境でカットオーバーのドライランを必ず実施
  3. 当日は 2 人体制(操作者 + 確認者)
  4. リバースレプリケーション保険で初期化(数日〜数週間)

8. Datastream の事故ケース

事故 8.1 — Oracle LogMiner の負荷でソース DB 性能劣化 中頻度

症状: Datastream を有効化したら、オンプレ Oracle の CPU 利用率が 30% → 80% に上昇、OLTP のレイテンシ悪化。
Root Cause: Oracle LogMiner ベースの CDC はredo log の解析でソース DB に負荷がかかる。大量の DML がある DB ほど顕著。
再発防止:
  1. Oracle ソースは LogMiner より GoldenGate 連携を検討(追加コストあり)
  2. Datastream 有効化は OLTP オフピーク時間に
  3. ソース DB の CPU 余裕を 30% 以上残す
  4. 必要に応じてソース DB を読み取り専用スタンバイに変更

事故 8.2 — スキーマ変更が BigQuery に伝播せずクエリ失敗 中頻度

症状: ソース DB で ALTER TABLE ADD COLUMN を実施 → BigQuery で「column not found」エラー。
Root Cause: Datastream の DDL 伝播は限定的。複雑な ALTER は手動で BigQuery 側も対応必要。
再発防止:
  1. DDL 変更プロセスを変更管理に組み込み(CR で BigQuery 側の対応も含める)
  2. BigQuery テーブルの information_schema.columns を週次で diff
  3. シンプルな列追加なら自動伝播するが、複雑なものは要事前テスト

事故 8.3 — Datastream ストリーム停止に気付かず分析データが古いまま 中頻度

症状: 営業会議で「今日の売上 0 円」と報告 → 実は Datastream ストリームが 3 日前に停止していた。
Root Cause: ストリーム停止時のアラート設定なし。BigQuery には古いデータが残っているため気付きにくい。
再発防止:
  1. ストリーム状態 (state=FAILED/PAUSED) を Cloud Monitoring でアラート
  2. BigQuery 側に「最終更新時刻」テーブルを作り、定期的に古さを監視
  3. BIダッシュボードに「データ鮮度(X分前更新)」を必ず表示

9. 全DB横断の事故パターン

パターン A: コスト爆発

共通原因: 横断対策: Budget Alert を必ず 3 段(50/80/100%)で設定、定期コストレビュー、夜間や開発環境はリソース削減

パターン B: 「マネージドだから大丈夫」過信

共通原因: GCP マネージド DB を「障害も自動で対応してくれる」と思い込み、ヘルスチェック・アラート・Runbook を準備しない。 横断対策: マネージドでも SLO/SLI を自前で測定、Runbook 作成、年 1 回の障害訓練(DR ドリル)

パターン C: 開発環境と本番環境の差

共通原因: 横断対策: Terraform で構成共通化、本番相当の ステージング環境を維持

パターン D: 移行・アップグレード時の事故

共通原因: メジャーバージョンアップやリージョン移行で「テスト不足」「ロールバック計画不在」。 横断対策: Blue-Green パターン、ステージング ドライラン切り戻し計画書を運用標準化

パターン E: バックアップが取れていなかった

共通原因: バックアップは取っているが、復元テストをしていない。いざ復元したら破損していた。 横断対策: 四半期に 1 回、別環境にバックアップから復元 + 整合性検証

📋 試験での出題傾向

PCDBE 試験では、上記の事故ケースをシナリオ問題として出題することが多い。 本ページの事故ケースを「現場で見た / 自分が起こしうる事故」として読むと、シナリオ問題が解きやすくなる。