コンテンツにスキップ

Feature 36: 自動リカバリーシステム

Author: Masahiro Aoki

実装日: 2026年2月20日
バージョン: 1.0.0
ステータス: ✅ 実装済み

概要

EvoSpikeNet の自動リカバリーシステム(Feature 36)は、AI ベースの異常検知と自動プレイブック実行を組み合わせ、システム障害の平均復旧時間(MTTR)を 80% 削減することを目的としています。

バックグラウンドで継続的にシステムメトリクスを監視し、異常を検知した場合は根本原因を分析して事前定義されたリカバリープレイブックを自動実行します。


アーキテクチャ

システムメトリクス
      │
      ▼
┌─────────────────┐
│ AnomalyDetector  │  ← Z スコア + EWMA による異常検知
│ (per metric)     │
└────────┬────────┘
         │ 異常検出
         ▼
┌─────────────────┐
│ RootCauseAnalyzer│  ← ルールベース根本原因分析
└────────┬────────┘
         │ FailureCategory
         ▼
┌─────────────────┐
│ Recovery         │  ← プレイブック選択・実行
│ Playbooks        │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│ Incident         │  ← インシデント記録・追跡
│ Tracking         │
└─────────────────┘

コアコンポーネント

AnomalyDetector

Z スコアおよび EWMA(指数加重移動平均)を用いてメトリクスの異常を検知します。 インスタンス化時にはウィンドウ長のみを指定し、しきい値等はクラス定数で制御されます。

<!-- from evospikenet.auto_recovery import AnomalyDetector -->

# デフォルトの 60 秒窓を使用
# Z_THRESHOLD=3.0, EWMA_ALPHA=0.15, MIN_SAMPLES=10 はクラス属性として定義
# 必要であればサブクラス化して上書きできます。
detector = AnomalyDetector(window=60)

# メトリクス値を更新し、異常を検出(True が返れば異常)
is_anomaly = detector.update("cpu_percent", 95.0)

主要プロパティ:

属性 デフォルト 説明
AnomalyDetector.Z_THRESHOLD 3.0 異常判定の Z スコア閾値
AnomalyDetector.EWMA_ALPHA 0.15 EWMA の平滑化係数
AnomalyDetector.MIN_SAMPLES 10 異常判定に必要な最小サンプル数
window (コンストラクタ引数) 60 履歴を保持するサンプル数

RootCauseAnalyzer

収集したメトリクスから障害カテゴリ、信頼度、説明を判定します。

<!-- TODO: update or remove - import failrt RootCauseAnalyzer, FailureCategory -->

analyzer = RootCauseAnalyzer()
category, confidence, explanation = analyzer.analyze({
    "cpu_percent": 95.0,
    "memory_percent": 45.0,
    "db_connected": True,
    "error_rate": 0.05,
})
# → (FailureCategory.CPU_OVERLOAD, 0.80, "CPU at 95.0%")

判定可能な障害カテゴリと基準:

カテゴリ 説明 判定条件 (analyze 実装)
memory_exhaustion メモリ枯渇 memory_percent ≥ 85%
oom_kill OOM キルリスク memory_percent ≥ 95%
cpu_overload CPU 過負荷 cpu_percent ≥ 95%
disk_full ディスク容量不足 disk_percent ≥ 90%
database_error DB 接続障害 db_connected == False
zenoh_disconnect Zenoh 切断 zenoh_connected == False
model_crash モデルクラッシュ model_ready == False
unknown その他/不明 上記以外、エラーレートが高い場合など

Recovery Playbooks

障害カテゴリごとに試みられる自動回復アクションの順序リストを定義します。

回復アクション 説明
RESTART_SERVICE サービスの再起動
RELOAD_MODEL モデルの再読込
RESTORE_SNAPSHOT スナップショットから復元
SCALE_DOWN リソース削減
CLEAR_CACHE キャッシュクリア
RECONNECT_ZENOH Zenoh 再接続
RECONNECT_DB DB 再接続
FREE_DISK ディスク空き容量確保
NOTIFY_ONLY 非常時に通知のみ実施(オペレーターへ)

AutoRecoveryEngine

バックグラウンドスレッドでメトリクスを監視し、インシデントライフサイクルを管理します。

<!-- モジュール 'evospikenet' が見つかりませんパッケージ内の移動/名前変更を確認してください -->
<!-PIサーバー起動時に自動実行
auto_recovery_engine.start()

# メトリクスを手動で報告(インシデントが作成された場合は返す)
incident = auto_recovery_engine.report_metrics(
    cpu_percent=45.0,
    memory_percent=60.0,
    disk_percent=55.0,
    db_connected=True,
    zenoh_connected=True,
    model_ready=True,
    error_rate=0.01,
)

# インシデント一覧取得
incidents = auto_recovery_engine.get_incidents()

# インシデントステータス変更
auto_recovery_engine.acknowledge_incident("incident-id")
auto_recovery_engine.resolve_incident("incident-id", "手動でプロセスを再起動")

REST API

GET /api/recovery/status

リカバリーエンジンの現在のステータスを返します。

レスポンス例:

{
  "total_incidents": 12,
  "open_incidents": 1,
  "acknowledged_incidents": 0,
  "resolved_incidents": 9,
  "auto_resolved_incidents": 2,
  "mttr_seconds": 145.2,
  "monitoring_interval_seconds": 30,
  "enabled_categories": ["cpu_overload", "memory_exhaustion", "database_error"]
}

GET /api/recovery/incidents

クエリパラメータ: status, severity, limit

GET /api/recovery/incidents/{id}

POST /api/recovery/incidents/{id}/acknowledge

POST /api/recovery/incidents/{id}/resolve

リクエストボディ (任意):

{ "resolution_note": "手動でサービスを再起動しました" }

POST /api/recovery/trigger

メトリクスをもとに手動で異常診断をトリガーします。

リクエストボディ:

{
  "cpu_percent": 95.0,
  "memory_percent": 80.0,
  "disk_percent": 60.0,
  "db_connected": false,
  "zenoh_connected": true,
  "model_ready": true,
  "error_rate": 0.15
}

レスポンス (インシデントあり):

{
  "status": "incident_created",
  "incident": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "category": "database_error",
    "severity": "critical",
    "status": "open",
    "actions_taken": ["RECONNECT_DB", "NOTIFY_ONLY"]
  }
}

レスポンス (正常):

{ "status": "no_anomaly_detected" }


設定

config/settings.yaml (各プロジェクトで任意に読込):

auto_recovery:
  enabled: true
  monitoring_interval_seconds: 30   # AutoRecoveryEngine.MONITORING_INTERVAL
  state_file: "data/recovery/auto_recovery_state.json"  # AutoRecoveryEngine.STATE_FILE
  detector_window: 60              # AnomalyDetector の履歴長
  thresholds:
    cpu_percent: 90.0
    memory_percent: 85.0
    disk_percent: 90.0
    error_rate: 0.1

インシデント構造

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "category": "memory_exhaustion",
  "severity": "high",
  "status": "open",
  "message": "Memory usage abnormally high: 92.3%",
  "detected_at": "2026-02-20T10:00:00Z",
  "resolved_at": null,
  "ttd_seconds": null,
  "ttr_seconds": null,
  "actions_taken": ["CLEAR_CACHE", "NOTIFY_ONLY"],
  "root_cause": "memory_exhaustion",
  "metrics_snapshot": {
    "memory_percent": 92.3,
    "cpu_percent": 45.0
  }
}

ステータス遷移:

open → acknowledged → resolved
 └──────────────────→ auto_resolved


テスト

# ユニットテスト
pytest tests/unit/test_auto_recovery.py -v

# 結合テスト
pytest tests/integration/test_features_36_39_40_integration.py::TestAutoRecoveryEndpoints -v

# システムテスト
pytest tests/system/test_features_36_39_40_system.py::TestE2EIncidentAuditFlow -v

# 性能テスト
pytest tests/performance/test_features_36_39_40_performance.py::TestAutoRecoveryEnginePerformance -v

関連ドキュメント