メインコンテンツまでスキップ

カオスエンジニアリング

本番環境で起こりうる障害を意図的に注入し、システムの耐障害性を検証する手法を学びます。

前提: 負荷テストObservability 基礎 を読んでから本ドキュメントを読むと、より理解が深まります。


なぜカオスエンジニアリングが必要か

負荷テストは「どこまで耐えられるか」を測定します。カオスエンジニアリングは「壊れたときにどうなるか」を検証します。

┌───────────────────────────────────────────────────────────────┐
│ 負荷テスト vs カオスエンジニアリング │
├───────────────────────────────────────────────────────────────┤
│ │
│ 負荷テスト: │
│ 「正常な状態で、どこまで耐えられるか?」 │
│ → スループット限界、飽和点、ボトルネック特定 │
│ │
│ カオスエンジニアリング: │
│ 「異常な状態で、正しく振る舞えるか?」 │
│ → 障害時の挙動確認、フォールバック検証、回復性 │
│ │
│ 両方必要。負荷テストが「晴れの日」のテストなら、 │
│ カオスエンジニアリングは「嵐の日」のテスト。 │
│ │
└───────────────────────────────────────────────────────────────┘

IdP/認証基盤は全サービスの入口です。IdPが止まると、連携する全サービスのログイン・API呼び出しが止まります。だからこそ「壊れたときにどうなるか」を事前に知っておく必要があります。


カオスエンジニアリングの原則

  1. 定常状態の仮説を立てる — まず「正常とは何か」をSLI/SLOで定義する
  2. 実世界のイベントを注入する — 実際に起こりうる障害を再現する
  3. 本番に近い環境で実験する — 開発環境では見つからない問題がある
  4. 爆発半径を最小化する — 影響範囲を限定してから始める
  5. 自動化して継続的に実行する — 一度きりではなく、回帰的に検証する

障害の分類と注入手法

インフラ障害

障害注入手法検証観点
Pod/コンテナの強制停止kubectl delete pod、Chaos Mesh の PodChaos残りのPodで処理継続できるか
ノード障害ノードのcordon + drainPod再配置後にサービス復旧するか
ディスクI/O遅延Chaos Mesh の IOChaosログ書き込み遅延がリクエスト処理に影響しないか

ネットワーク障害

障害注入手法検証観点
レイテンシ注入tc netem delay、Chaos Mesh の NetworkChaosタイムアウトが適切に効くか
パケットロスtc netem lossリトライで回復するか、リトライ嵐にならないか
DNS障害DNS応答の遅延/失敗注入キャッシュが機能するか
特定ホストへの接続断iptables、NetworkChaos外部IdP連携の障害が他機能に波及しないか

アプリケーション障害

障害注入手法検証観点
スレッドプール枯渇意図的にスロークエリを注入タイムアウトで解放されるか
メモリ圧迫Stress-ng、コンテナのメモリ制限縮小OOM Killer発動後に再起動するか
依存サービスの5xxモック/プロキシで503を返すエラーハンドリングが適切か

データストア障害

障害注入手法検証観点
DB接続断ネットワーク遮断、DBプロセス停止接続プールが回復するか
フェイルオーバー発生Aurora/RDSの手動フェイルオーバー一時エラー後に自動回復するか
接続プール枯渇最大接続数を極端に小さく設定適切なエラーレスポンスを返すか

IdP固有の実験シナリオ

IdPの特性上、特に重要な4つのシナリオを紹介します。

1. 外部IdP連携の障害

Federation機能(Google、Azure AD等との連携)で外部通信が発生します。

実験:

  • 外部IdPのUserInfoエンドポイントに3秒の遅延を注入
  • JWKSエンドポイントへの接続を遮断
  • 外部IdPが503を返す状態を作る

検証観点:

  • タイムアウト設定は適切か(デフォルト無制限になっていないか)
  • JWKSのキャッシュは機能するか(接続断でも既存の鍵で検証を継続できるか)
  • 外部IdPの障害がパスワードログインなど他の認証方式に波及しないか

2. CIBA通知の障害

CIBAフローではFCM等を通じてデバイスにプッシュ通知を送信します。

実験:

  • FCMへの送信を遅延/失敗させる
  • Polling中にidp-serverのPodを再起動する

検証観点:

  • 通知失敗時にクライアントへ適切なエラーレスポンスを返すか
  • Poll/Ping/Pushの各モードで障害時の挙動が正しいか
  • auth_req_idの状態が再起動後も保持されるか

3. マルチテナント環境での障害伝播

マルチテナントIdPでは、1テナントの問題が他テナントに影響しないことが重要です。

実験:

  • 特定テナントに対して大量リクエストを送る(ノイジーネイバー)
  • 特定テナントのDB操作を意図的に遅延させる

検証観点:

  • 他テナントのレイテンシ・エラーレートに影響が出ないか
  • テナント間のリソース分離は機能しているか

4. トークン発行中のDB障害

トークン発行はDBへの書き込みを伴うトランザクションです。

実験:

  • アクセストークン書き込み中にDB接続を切断
  • リフレッシュトークンのローテーション中にフェイルオーバーを発生させる

検証観点:

  • トランザクションの整合性は保たれるか(中途半端な状態にならないか)
  • クライアントにリトライ可能なエラーが返されるか
  • フェイルオーバー完了後に正常処理に復帰するか

主要ツール

ツール特徴対象環境
Chaos MeshKubernetes ネイティブ、CRDで障害を定義。Pod/Network/IO/DNS障害に対応Kubernetes
Litmus ChaosChaosHub でシナリオを共有可能。Argo Workflows と統合しやすいKubernetes
AWS Fault Injection ServiceAWSマネージド。EC2/ECS/RDS/ネットワーク障害に対応AWS
tc / iptablesOS標準ツール。軽量だが手動管理が必要Linux全般

Kubernetes環境であれば Chaos Mesh が第一選択肢です。CRDでYAML定義できるため、GitOpsとの相性が良く、CI/CDパイプラインに組み込めます。


実験の進め方

ステップ1: 定常状態を定義する

実験前に「正常とは何か」を定量的に定義します。

  • トークン発行: P99 < 500ms、エラーレート < 0.1%
  • 認可エンドポイント: P99 < 300ms
  • 全エンドポイント: HTTP 5xx率 < 0.01%

これがSLOです。実験中にこの値を監視し、障害注入の影響を測定します。

ステップ2: 仮説を立てる

実験には必ず仮説が必要です。「なんとなく壊してみる」ではありません。

例:

「DBレプリカが停止しても、フェイルオーバー完了(30秒以内)まで、エラーレートは1%以下に収まるはずだ」

ステップ3: 実験を設計する

┌───────────────────────────────────────────────────────────────┐
│ 実験設計テンプレート │
├───────────────────────────────────────────────────────────────┤
│ │
│ 障害: Aurora プライマリのフェイルオーバー │
│ 持続時間: フェイルオーバー完了まで(通常15-30秒) │
│ 対象: ステージング環境の idp-server │
│ 爆発半径: ステージング環境のみ │
│ │
│ 観測メトリクス: │
│ ・k6: エラーレート、P99レイテンシ │
│ ・HikariCP: active/pending 接続数 │
│ ・アプリログ: 例外の種類と頻度 │
│ │
│ 中止条件: エラーレート 5% 超過で即停止 │
│ ロールバック手順: フェイルオーバーの再実行でプライマリ復帰 │
│ │
└───────────────────────────────────────────────────────────────┘

ステップ4: 実行と観測

実験中は Grafana/Jaeger でリアルタイム監視します。障害注入の前後でメトリクスがどう変化したかを記録します。

観測のポイント:

  • 障害注入の瞬間にスパイクが出るか
  • スパイク後に自動回復するか、悪化し続けるか
  • 回復までにかかる時間はどのくらいか

ステップ5: 分析と改善

仮説と結果を比較します。

  • 仮説通り → レジリエンスが確認できた。結果を記録して次の実験へ
  • 仮説と異なる → 弱点が見つかった。対策を実装し、再実験で検証

実験結果の読み方

成功パターン

障害注入してもSLO維持。レジリエンスが確認できた状態:

  • Pod 1台停止 → 残りのPodで処理継続、エラーレート 0%
  • 外部IdP 3秒遅延 → タイムアウト(5秒)内で応答、ユーザーに軽微な遅延のみ

発見パターン(よくある弱点)

発見症状対策
タイムアウト未設定外部APIの遅延がリクエストスレッドを占有し続けるHttpClient にタイムアウトを明示設定
Circuit Breaker 未設定障害中の外部APIにリクエストを送り続けてカスケード障害Resilience4j 等で閾値を設定
リトライ嵐リトライが一斉に発生して障害が拡大Exponential Backoff + Jitter
コネクションリークフェイルオーバー中に例外が発生し、接続が返却されないtry-with-resources、プール監視
フェイルオーバー後の接続不良古い接続が残りDBエラーが続く接続検証クエリ(validation-query)の設定

アンチパターン(やってはいけないこと)

  • 本番で事前準備なしに実行 — 必ずステージング環境から始める
  • 中止条件を決めずに実行 — 想定外の影響が出たときに止められない
  • 結果を記録しない — 再現できなくなり、改善の効果検証もできない
  • 改善せずに終わる — 弱点を見つけただけでは意味がない

まとめ

実験カテゴリ検証観点期待する結果
インフラ障害(Pod停止)冗長性残りのPodで無停止処理
ネットワーク障害(遅延・断)タイムアウト・フォールバック適切なタイムアウトで影響を限定
DB障害(フェイルオーバー)自動回復一時エラー後に自動復帰
外部IdP障害障害分離他の認証方式に影響なし
テナント間の障害伝播ノイジーネイバー耐性他テナントのSLO維持
トークン発行中の障害トランザクション整合性中途半端な状態にならない

関連ドキュメント