【本番障害】Protocol Buffer破壊的変更で全サービス停止→復旧までの72時間地獄体験記
プロローグ:軽く考えていた金曜日の夕方
2025年8月23日(金曜日)午後4時30分
「ちょっとAPIを整理するだけだから、30分で終わるでしょ」
そんな軽い気持ちで、Protocol BufferのAPIから不要なフィールドを削除した私。まさか、この判断が72時間に及ぶ地獄の始まりだとは思いもしませんでした。
これは、その時の血と汗と涙の記録です。
第一章:「軽微な変更」の大誤算
背景:不要フィールドの削除計画
私たちのマイクロサービス環境では、ユーザーサービスのAPIが肥大化していました。
1
2
3
4
5
6
7
8
9
|
// user_service.proto (v1.5.0) - 変更前
message User {
string id = 1;
string name = 2;
string email = 3;
int32 age = 4; // ← これを削除予定
string department = 5; // ← これも削除予定
string legacy_format = 6; // ← これも削除予定
}
|
削除理由:
age
: プライバシー要件により廃止
department
: 新しいプロフィールシステムに統合済み
legacy_format
: 旧システム用で現在未使用
「誰も使ってないフィールドだし、さくっと削除しちゃお」
致命的な判断:いきなりの削除実行
午後4時35分 - 運命の commit
1
2
3
|
git add user_service.proto
git commit -m "Remove unused fields from User message"
git push origin main
|
1
2
3
4
5
6
7
|
// user_service.proto (v2.0.0) - 変更後
message User {
string id = 1;
string name = 2;
string email = 3;
// age, department, legacy_format を完全削除
}
|
「よし、これでスッキリした!」
午後4時50分:最初の異変
Slack に最初のアラートが。
1
2
3
4
|
🔥 AlertManager
[CRITICAL] user-service: Health check failed
- Error rate: 15% → 45%
- Response time: 200ms → TIMEOUT
|
「あれ?何かおかしいな…でも金曜の夕方だし、月曜に見よう」
これが、後に「人生最悪の判断」と呼ばれることになります。
第二章:金曜夜の地獄の始まり
午後6時:本格的な障害発生
1
2
3
4
5
6
|
🚨 PagerDuty Alert
[P1] PRODUCTION DOWN
- user-service: 100% error rate
- payment-service: dependency failure
- notification-service: cascade failure
- recommendation-service: data corruption
|
「え?え?なんで全部のサービスが?」
慌てて原因調査
ログ確認:
1
|
kubectl logs user-service-7d4f8b9c-xh2rl
|
1
2
3
4
5
|
ERROR: proto: cannot parse invalid wire-format data
ERROR: field 'age' not found in message User
ERROR: field 'department' not found in message User
ERROR: unmarshaling failed: unknown field
FATAL: service startup failed
|
「あ…まずい…」
午後7時:事態の深刻さを理解
影響範囲の調査結果:
- user-service: 完全停止(新しいprotoで起動不可)
- payment-service: ユーザー情報取得で例外発生
- notification-service: ユーザープロファイル参照エラー
- recommendation-service: age フィールド依存で計算不可
- analytics-service: department フィールド依存でレポート生成失敗
被害状況:
- 全ユーザーのログイン不可
- 決済処理完全停止
- 通知システム機能停止
- おすすめ機能全滅
- 管理画面アクセス不可
「これ…全サービス死んでる…」
午後7時30分:緊急事態宣言
CTOからの緊急召集。
「なぜ本番で破壊的変更を?影響調査は?段階的移行は?」
私:「すみません、軽微な変更だと思って…」
CTO:「軽微?全サービス停止が軽微?」
この時の絶望感は言葉にできません。
第三章:復旧作戦 - 第一夜の戦い
午後8時:緊急対策チーム結成
メンバー:
- CTO(指揮官)
- SRE リーダー(インフラ担当)
- バックエンドエンジニア 3名
- QA エンジニア 1名
- そして私(戦犯)
復旧戦略1:単純ロールバックの試行
「とりあえず前のバージョンに戻そう」
1
2
|
git revert HEAD
git push origin main
|
結果:
1
2
3
|
❌ FAILED: Container build failed
❌ Protocol buffer compilation error
❌ Service mesh configuration mismatch
|
「なんで戻らないの?」
判明した問題:
- 他のサービスが新しい proto を参照していた
- Kubernetes の ConfigMap が更新済み
- サービスメッシュのルーティング設定が変更されていた
復旧戦略2:緊急パッチの作成
1
2
3
4
5
6
7
8
9
10
11
|
// user_service.proto (v2.0.1) - 緊急パッチ版
message User {
string id = 1;
string name = 2;
string email = 3;
// 緊急復旧:削除したフィールドを復活
int32 age = 4; // 緊急復旧
string department = 5; // 緊急復旧
string legacy_format = 6; // 緊急復旧
}
|
午後11時30分 - デプロイ実行
結果:
1
2
3
4
5
|
✅ user-service: Started
✅ payment-service: Health check OK
❌ notification-service: Still failing
❌ recommendation-service: Data inconsistency
❌ analytics-service: Historical data corruption
|
「一部復旧したけど、まだ半分死んでる…」
深夜1時:現実の厳しさ
残る問題:
- 削除期間中のデータ欠損
- キャッシュに残る不正データ
- 依存サービスの内部状態不整合
- ログ解析システムのスキーマ不一致
「これ…復旧に何日かかるんだ…」
深夜3時:第一夜の終了
進捗:
- ユーザーログイン: 50%復旧
- 決済処理: 30%復旧
- 通知システム: 10%復旧
- その他: ほぼ停止状態
徹夜明けの疲労と絶望感で、思考能力も低下。
「明日も長い戦いになる…」
第四章:土曜日 - データ整合性との戦い
午前8時:新たな問題発覚
一晩で状況はさらに悪化していました。
新たに発見された問題:
1
2
3
4
5
|
# エラーログの嵐
ERROR: User age calculation failed: field missing
ERROR: Department-based routing failed: null value
ERROR: Legacy format parser: unexpected end of data
ERROR: Cache invalidation failed: schema mismatch
|
データ整合性の破綻
最も深刻だった問題:
1
2
3
4
5
|
-- analytics データベース
SELECT user_id, age, department FROM user_analytics
WHERE created_at > '2025-08-23 16:30:00';
-- 結果: 3時間分のデータで age と department が NULL
|
「3時間で30万件のデータが破損…これどうやって修復するんだ…」
修復戦略の検討
選択肢1: バックアップからの復旧
- 影響:3時間分のデータロス
- 作業時間:6-8時間
- リスク:中
選択肢2: 手動データ補完
- 影響:データロスなし
- 作業時間:20-30時間
- リスク:高(人的ミス)
選択肢3: 機械学習による補完
- 影響:推定値での補完
- 作業時間:10-15時間
- リスク:中(推定誤差)
午前11時:修復戦略の決定
チームで協議の結果、組み合わせ戦略を採用。
1
2
3
|
重要データ(決済関連): バックアップ復旧
分析データ: ML補完
ログデータ: 手動補完
|
データ修復作業の開始
12時間に及ぶデータ修復祭り:
1
2
3
4
5
6
7
8
9
10
|
# 決済データの復旧
pg_restore --data-only payment_backup_20250823_1630
# 分析データの ML補完
python ml_data_restoration.py \
--missing-fields age,department \
--time-range "2025-08-23 16:30 - 19:30"
# ログデータの手動修復
./manual_log_fix.sh user-service 20250823
|
土曜夜:70%復旧達成
午後11時の状況:
- ユーザーログイン: 95%復旧
- 決済処理: 90%復旧
- 通知システム: 70%復旧
- 分析システム: 60%復旧(データ補完中)
「ようやく光が見えてきた…でもまだ終わらない」
第五章:日曜日 - 完全復旧への道のり
午前9時:最後の難敵
残る問題は依存関係の複雑な絡み合いでした。
1
2
3
4
5
6
7
|
recommendation-service
↓ (depends on)
user-profile-service
↓ (depends on)
user-service
↓ (depends on)
identity-service
|
依存関係地獄の解決
各サービスを依存順序に従って段階的に復旧。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
# Phase 1: 基盤サービス
kubectl rollout restart deployment/identity-service
kubectl wait --for=condition=available deployment/identity-service
# Phase 2: コアサービス
kubectl rollout restart deployment/user-service
kubectl wait --for=condition=available deployment/user-service
# Phase 3: 依存サービス
kubectl rollout restart deployment/user-profile-service
kubectl wait --for=condition=available deployment/user-profile-service
# Phase 4: 上位サービス
kubectl rollout restart deployment/recommendation-service
kubectl wait --for=condition=available deployment/recommendation-service
|
午後3時:ついに完全復旧
全サービス正常稼働確認:
1
2
3
4
5
|
✅ user-service: 100% healthy
✅ payment-service: 100% healthy
✅ notification-service: 100% healthy
✅ recommendation-service: 100% healthy
✅ analytics-service: 100% healthy
|
「やった…やっと終わった…」
午後4時:事後対応
復旧完了の社内通達:
【障害復旧完了】
8/23 16:30 〜 8/25 16:00 に発生していた全サービス停止障害が復旧しました。
原因:Protocol Buffer スキーマの破壊的変更による互換性破綻
影響時間:48時間
影響範囲:全ユーザー、全サービス
詳細な原因分析と再発防止策は後日共有いたします。
第六章:事後分析 - 何がいけなかったのか
根本原因分析
技術的原因:
- 破壊的変更を段階的移行なしで実行
- 依存関係の把握不足
- 影響範囲の調査不足
- ロールバック戦略の未検討
プロセス的原因:
- 変更管理プロセスの軽視
- コードレビューの形骸化
- テスト環境での検証不足
- 本番環境への直接反映
組織的原因:
- 破壊的変更に対する理解不足
- リスク意識の欠如
- 緊急対応体制の不備
被害の詳細
ビジネスインパクト:
- 売上損失:約$50,000(48時間の停止)
- 顧客問い合わせ:2,847件
- 解約申請:127件
- SNSでの炎上:Twitter で 1,234件の苦情
技術的コスト:
- エンジニア工数:240時間(5名×48時間)
- インフラ費用:$3,200(復旧作業用リソース)
- データ修復コスト:$8,500(ML処理費用)
総コスト:約$61,700
最も痛かった教訓
「Protocol Bufferの破壊的変更は、絶対に軽く扱ってはいけない」
この当たり前のことを、$61,700と48時間の地獄で学ぶことになったのです。
第七章:再発防止策 - 段階的変更管理の確立
新しい変更管理プロセス
この障害を受けて、厳格な段階的変更管理プロセスを確立しました。
Phase 0: 計画・準備段階
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
## 破壊的変更チェックリスト
### 事前調査
- [ ] 影響範囲の完全な調査完了
- [ ] 依存サービスリストの作成
- [ ] 既存クライアントの特定
- [ ] ロールバック戦略の策定
- [ ] データ移行計画の作成
### リスク評価
- [ ] ビジネスインパクト評価
- [ ] 技術的リスク評価
- [ ] 復旧時間見積もり
- [ ] 代替案の検討
### 承認プロセス
- [ ] テックリード承認
- [ ] CTO承認
- [ ] ビジネス側承認
|
Phase 1: 非推奨マーク・新API追加
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
// 新しいアプローチ(段階的変更)
message User {
string id = 1;
string name = 2;
string email = 3;
// 段階1:非推奨マーク(削除予定を明示)
int32 age = 4 [deprecated = true]; // 削除予定: 2025-12-31
string department = 5 [deprecated = true]; // 削除予定: 2025-12-31
string legacy_format = 6 [deprecated = true]; // 削除予定: 2025-12-31
// 新フィールド追加
string birth_date = 7; // age の代替
UserProfile profile = 8; // department の代替
}
|
Phase 1での運用:
- 期間:3ヶ月
- 監視:非推奨API使用状況の継続監視
- 通知:依存チームへの移行案内
- サポート:移行支援の提供
Phase 2: 移行促進期間
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
// Phase 2: 移行期間中の設定
message User {
string id = 1;
string name = 2;
string email = 3;
// 段階2:警告レベル引き上げ
int32 age = 4 [deprecated = true]; // 警告:2025-11-30削除
string department = 5 [deprecated = true]; // 警告:2025-11-30削除
string legacy_format = 6 [deprecated = true]; // 警告:2025-11-30削除
string birth_date = 7;
UserProfile profile = 8;
}
|
Phase 2での運用:
- 期間:2ヶ月
- 目標:非推奨API使用率 < 10%
- 警告:ログレベルでの警告出力強化
- 支援:移行が困難なチームへの個別支援
Phase 3: 削除実行
1
2
3
4
5
6
7
8
9
10
11
12
|
// Phase 3: 安全な削除
message User {
// 削除済みフィールドの番号を予約
reserved 4, 5, 6;
reserved "age", "department", "legacy_format";
string id = 1;
string name = 2;
string email = 3;
string birth_date = 7;
UserProfile profile = 8;
}
|
Phase 3での運用:
- 実施時期:非推奨API使用率 < 5% を確認後
- メジャーバージョンアップとして実施
- reserved による番号保護
- 詳細なリリースノート作成
自動化ツールの導入
手動プロセスだけでは限界があるため、自動化ツールも導入しました。
破壊的変更検出ツール
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
# Proto互換性チェック
proto-compatibility-check \
--old-proto user_service_v1.proto \
--new-proto user_service_v2.proto \
--strict-mode
# 出力例
❌ BREAKING CHANGE DETECTED:
- Field 'age' (4) removed from message User
- Field 'department' (5) removed from message User
- Field 'legacy_format' (6) removed from message User
⚠️ IMPACT ANALYSIS:
- Affected services: 5 services
- Estimated impact: HIGH
- Recommended approach: Gradual migration
🔧 SUGGESTED STEPS:
1. Mark fields as deprecated
2. Add alternative fields
3. Monitor usage for 3 months
4. Remove after migration complete
|
依存関係追跡システム
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# サービス依存関係の可視化
service-dependency-tracker analyze user-service
# 出力例
📊 DEPENDENCY MAP:
user-service (Protocol Buffer: user.proto)
├── payment-service (uses: User.age for risk calculation)
├── notification-service (uses: User.department for routing)
├── recommendation-service (uses: User.age for algorithm)
├── analytics-service (uses: User.department for reports)
└── legacy-system (uses: User.legacy_format for integration)
⚠️ BREAKING CHANGE IMPACT:
- Field 'age': 2 critical services affected
- Field 'department': 2 services affected
- Field 'legacy_format': 1 legacy system affected
|
運用監視システム
リアルタイム監視ダッシュボード
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
## 破壊的変更管理ダッシュボード
### 現在のステータス
- Phase 1 (非推奨マーク): user_service v2.1.0
- 削除予定日: 2025-12-31
- 残り日数: 108日
### 移行進捗
- user_service.User.age使用率: 23% ↓ (目標: <10%)
- user_service.User.department使用率: 15% ↓ (目標: <10%)
- user_service.User.legacy_format使用率: 3% ✅ (目標達成)
### アラート
⚠️ payment-service: age フィールド使用量が増加中
✅ notification-service: department フィールド移行完了
|
第八章:新プロセスの効果と学び
初回適用:success story
新プロセスを初めて適用したのは、3ヶ月後の order-service の変更でした。
変更内容:
payment_method
フィールドの削除
- 新しい
payment_info
構造体への移行
結果:
- 計画期間:6ヶ月
- 実際の削除実行:無事故で完了
- ダウンタイム:0分
- ビジネスインパクト:なし
「やっと正しいやり方を覚えた…」
チーム文化の変化
この障害を境に、チーム全体の意識が劇的に変わりました。
Before(障害前):
1
2
3
|
エンジニア: 「ちょっと変更するだけだから大丈夫でしょ」
レビュアー: 「コードは問題ないですね、LGTM」
リリース: 「金曜の夕方だけど、軽微だからリリースしちゃお」
|
After(現在):
1
2
3
|
エンジニア: 「これって破壊的変更になりませんか?影響調査します」
レビュアー: 「依存関係チェックツール回しましたか?段階的移行計画は?」
リリース: 「破壊的変更は必ず月曜午前中。復旧チーム待機で」
|
予期しない副次効果
段階的変更管理を導入した結果、思わぬ良い効果もありました。
1. コードの品質向上
- 破壊的変更を避けるため、より慎重な設計
- 将来の拡張性を考慮した API設計
- ドキュメント品質の向上
2. チーム間コミュニケーション改善
- 依存関係の可視化により連携強化
- 変更計画の事前共有によるフィードバック増加
- 問題の早期発見と解決
3. 運用品質の向上
- 段階的リリースによる品質確保
- 監視体制の強化
- インシデント対応能力の向上
第九章:同じ間違いを犯さないために
他チームへの知見共有
この体験を社内で共有したところ、他のチームからも同様の経験談が多数寄せられました。
よくある失敗パターン:
-
「軽微な変更」の過信
1
2
|
「フィールド1つ削除するだけだから」
→ 実際は10のサービスに影響
|
-
金曜日の変更
1
2
|
「金曜に変更して週末に様子見」
→ 週末障害で緊急召集
|
-
テスト環境での検証不足
1
2
|
「本番環境でしか起きない問題があった」
→ 本番環境特有の依存関係
|
-
ロールバック戦略の未検討
1
2
|
「戻せばいいでしょ」
→ 相互依存で戻せない状況
|
チェックリストの標準化
破壊的変更実施チェックリスト(社内標準):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
## Phase 0: 事前準備(必須)
- [ ] 破壊的変更影響調査完了
- [ ] 依存サービス一覧作成(最低10サービス調査)
- [ ] 既存クライアント使用状況調査
- [ ] ビジネス影響度評価(売上・顧客への影響)
- [ ] テックリード・CTO承認取得
## Phase 1: 非推奨化(3ヶ月以上)
- [ ] deprecated マーク追加
- [ ] 代替手段の提供
- [ ] 移行ガイド作成・共有
- [ ] 使用状況監視開始
- [ ] 定期的な移行状況レポート
## Phase 2: 移行促進(2ヶ月以上)
- [ ] 使用率50%以下を確認
- [ ] 警告レベル引き上げ
- [ ] 個別チーム移行支援
- [ ] 削除予定日の明確化・通知
## Phase 3: 削除実行
- [ ] 使用率5%以下を確認
- [ ] メジャーバージョンアップとして実施
- [ ] reserved設定でフィールド保護
- [ ] 復旧チーム待機での実行(平日午前中)
- [ ] 段階的ロールアウト(Canary → Blue-Green)
|
教育プログラムの実施
新人研修での必修コース:「Protocol Buffer 破壊的変更の恐怖」
実際の障害ログを使った2時間の研修プログラムを作成しました。
研修内容:
- 実際の障害ログ分析(45分)
- 正しい変更管理手法(30分)
- ハンズオン実習(30分)
- 質疑応答(15分)
研修効果:
- 受講者の90%が「破壊的変更の怖さを理解した」と回答
- 新人による同種の事故:0件(6ヶ月間)
まとめ:$61,700と48時間で学んだこと
最も重要な教訓
「軽微な変更」などというものは存在しない。特にProtocol Bufferにおいては。
あの金曜日の夕方、私は「30分で終わる簡単な作業」だと思っていました。
結果:
- 48時間の全サービス停止
- $61,700の損失
- 顧客からの信頼失墜
- チーム全体への迷惑
技術的な学び
-
段階的変更管理は必須
- deprecated → 移行 → reserved のフロー
- 最低6ヶ月の移行期間確保
- 使用状況の継続監視
-
依存関係の可視化
- サービス間依存の完全な把握
- 影響範囲の事前調査
- 自動化ツールによる継続監視
-
ロールバック戦略
- 簡単に戻せない場合の対処法
- 段階的復旧の手順確立
- 緊急事態対応チームの編成
プロセス的な学び
-
変更管理プロセスの重要性
- 技術的レビューだけでは不十分
- ビジネス影響度の評価必須
- 段階的承認プロセスの確立
-
チームコミュニケーション
- 依存チームへの早期共有
- 移行支援の積極的実施
- 定期的な進捗レポート
-
リスク管理
- 最悪ケースシナリオの想定
- 復旧時間の見積もり
- ビジネス継続計画との連携
人生的な学び
「面倒くさい」と思うプロセスにこそ、価値がある。
段階的変更管理は確かに面倒です。6ヶ月かけて1つのフィールドを削除するなんて、効率的には見えません。
でも、その「面倒くささ」が、$61,700の損失と48時間の地獄を防いでくれるのです。
最後に:同じ過ちを犯さないために
この記録を読んでいるあなたへ。
もしも今、「これくらい軽微だから大丈夫」と思っている変更があるなら、立ち止まってください。
- 本当に軽微ですか?
- 依存関係を全て把握していますか?
- ロールバック戦略はありますか?
- 金曜日の夕方ではありませんか?
私と同じ過ちを犯す必要はありません。
段階的変更管理、面倒だけど絶対に価値がある。
これが、$61,700と48時間の地獄から学んだ、最も大切な教訓です。
追記(2025年9月):
この障害から1年が経ちました。新しい変更管理プロセスの導入により、Protocol Buffer関連の障害は0件。チーム全体の品質意識も格段に向上しました。
あの時の地獄があったからこそ、今の安定した運用があります。
失敗を恐れず、しかし失敗から学ぶことの大切さを、改めて実感しています。
関連記事:
注意: この記事は実際の障害体験を基にしていますが、具体的なサービス名や数値は一部変更しています。