Mímisbrunnr知恵の泉

← MLOps 一覧

🎓 レベル:発展 | 重要度:A(必須)

📎 前提:モデルレジストリとモデルのライフサイクル | 関連:本番モデルの監視

要点(BLUF)

1. なぜ段階を踏むのか

オフライン評価で良くても、本番では未知の入力・負荷・統合不具合が待っています。一気に切り替えると、問題が起きたとき全ユーザーが被害を受けます。リリース戦略は「影響範囲を絞りながら、技術→安全→効果の順に確かめる」リスク管理です。

2. 3つの戦略

flowchart LR
  S["シャドー:影で並走"] -->|"技術的に健全"| C["カナリア:少数に先行"]
  C -->|"少数で問題なし"| AB["A-Bテスト:効果測定"]
  AB -->|"有意に改善"| FULL["全面展開"]
  C -.->|"異常検知"| RB["自動ロールバック"]
  AB -.->|"改善せず/悪化"| RB
戦略やり方答える問いユーザー影響
シャドー本番入力を新モデルにも流すが応答は使わない壊れず動くか・遅延は許容内かなし(影で並走)
カナリア少数(例5%)に新モデルを適用し段階拡大少数で問題が出ないか少数のみ
A-Bテストトラフィックを分割し指標を統計比較本当に良くなったか半数程度

3. シャドーとカナリアの違い

4. 動く最小例:カナリアの自動ロールバック判定

カナリア中の指標(エラー率・遅延・主要メトリクス)を監視し、ガード条件を割ったら自動でロールバック判定を出す最小ロジックです。

def canary_decision(baseline, canary, guards):
    """baseline/canary: 観測指標の辞書。guards: 許容条件。
    戻り値: ('promote'|'hold'|'rollback', 理由のリスト)"""
    reasons = []
    # エラー率:ベースライン比でguard倍を超えたら危険
    if canary["error_rate"] > baseline["error_rate"] * guards["error_ratio_max"]:
        reasons.append(f"エラー率悪化 {canary['error_rate']:.3f} "
                       f"> {baseline['error_rate']*guards['error_ratio_max']:.3f}")
    # 遅延:絶対上限
    if canary["p99_latency_ms"] > guards["p99_latency_max"]:
        reasons.append(f"p99遅延超過 {canary['p99_latency_ms']} "
                       f"> {guards['p99_latency_max']}")
    # 主要メトリクス:ベースラインを下回ったら悪化
    if canary["conversion"] < baseline["conversion"] - guards["metric_drop_max"]:
        reasons.append(f"主要指標低下 {canary['conversion']:.3f} "
                       f"< {baseline['conversion']-guards['metric_drop_max']:.3f}")
    if reasons:
        return "rollback", reasons
    return "promote", ["全ガード条件を満たした"]

baseline = {"error_rate": 0.010, "p99_latency_ms": 80, "conversion": 0.120}
guards = {"error_ratio_max": 2.0, "p99_latency_max": 150, "metric_drop_max": 0.005}

# ケース1:健全なカナリア
good = {"error_rate": 0.012, "p99_latency_ms": 90, "conversion": 0.123}
print("ケース1:", canary_decision(baseline, good, guards))

# ケース2:エラー率・遅延・主要指標がすべて悪化したカナリア
bad = {"error_rate": 0.030, "p99_latency_ms": 180, "conversion": 0.110}
print("ケース2:", canary_decision(baseline, bad, guards))

出力:

ケース1: ('promote', ['全ガード条件を満たした'])
ケース2: ('rollback', ['エラー率悪化 0.030 > 0.020', 'p99遅延超過 180 > 150', '主要指標低下 0.110 < 0.115'])

出力の意味:ケース1はエラー率・遅延・主要指標すべてが許容内なので「promote(拡大)」。ケース2はエラー率がベースラインの2倍超、p99遅延が上限超過、主要指標もベースライン-0.005の床を下回ったので「rollback」と3つの理由つきで判定されました。人間の判断を待たず、定義したガード条件で自動的に止める——これがカナリアを安全にする核です。効果の有無(A-Bテスト)はこの先、統計的に検証します。

5. 運用の勘所

なぜそうするのか

リリースを段階化するのは、「確実性が低いほど影響範囲を小さく」という原則です。新モデルが本番でどう振る舞うかは、出してみるまで完全には分かりません。だから最初は影響ゼロ(シャドー)で技術を確かめ、次に少数(カナリア)で安全を確かめ、最後に効果(A-Bテスト)を統計的に確かめる。各段階で「問題なし」を確認してから影響範囲を広げることで、避けられる障害を本番全体に波及させずに済みます。

⚠️ よくある落とし穴

対応 lab

関連ノート