Files
awoooi/docs/runbooks/RUNBOOK-OLLAMA-FAILOVER.md

11 KiB
Raw Blame History

RUNBOOK-OLLAMA-FAILOVER.md

Ollama 容災監控 Runbook

2026-04-26 P2.3 by Claude Sonnet 4.6 (tool-expert)

2026-06-04 Codex 更新ADR-110 現行順序為 GCP-A → GCP-B → 111 local → Gemini111 經 110:11437 Nginx proxy 進入,不直接由 K8s Pod 打 111。

對應告警規則: ops/monitoring/ollama_health_rules.yaml

對應 Dashboard: ops/monitoring/grafana/dashboards/ollama_failover.json


現行拓樸與一鍵診斷

現行 AI 推理順序:

順位 Provider 入口
1 GCP-A http://192.168.0.110:11435
2 GCP-B http://192.168.0.110:11436
3 111 local fallback http://192.168.0.110:11437192.168.0.111:11434
4 Gemini 只在三層 Ollama 都不可用後作最後備援

111 是 Mac / LaunchAgent 管理的 local fallback不要用舊的 systemctl / nvidia-smi 手順判斷它。若 11437502,優先分辨是 110 proxy 本身壞掉,還是 110 到 111 的 LAN/ARP 不通。

只讀診斷:

bash scripts/ops/ollama111-fallback-proxy-diagnose.sh

常見判讀:

證據 判讀 行動
ollama_gcp_a=upollama_gcp_b=up,但 ollama_local=down 第三層 fallback 單點故障,核心 AI lane 仍可用 不要改 provider order先修 111 主機或 LAN
110 ip neigh 192.168.0.111 INCOMPLETE 110 找不到 111 MAC通常是 111 關機、睡眠、Wi-Fi/LAN 斷線或 IP 漂移 恢復 111 電源/網路,再重跑診斷
110 direct 192.168.0.111:11434 OK127.0.0.1:11437 502 110 Nginx proxy 配置或程序異常 檢查 110-ollama-proxy.conf 與 Nginx reload
SSH 到 ollama-111-gpu OK127.0.0.1:11434 失敗 111 本機 Ollama 或 allowlist LaunchAgent 異常 檢查 com.momo.ollama111-allow-proxy 與 Ollama

Grafana Dashboard 使用說明

Dashboard 路徑:Ollama 容災監控uid: ollama-failover-p23 匯入方式Grafana UI → Dashboards → Import → Upload JSON file → 選 ops/monitoring/grafana/dashboards/ollama_failover.json

Panel 1 — Ollama 可用性 (Stat)

看什麼up{job=~"ollama_gcp_a|ollama_gcp_b|ollama_local|ollama_111"} × 100顯示每個 Ollama provider endpoint 的 scrape 存活狀態。

顏色 意義
綠色 100% Prometheus 探測正常,主機在線
黃色 部分 endpoint 離線,系統應進入容災
紅色 0% Ollama provider pool 全離線,高風險

注意:此面板反映 Prometheus scrape 狀態,需要 scrape job 命名對齊 ollama_gcp_a / ollama_gcp_b / ollama_local。 設定檔位於 ops/monitoring/generated/prometheus-scrape-generated.yaml


Panel 2 — 推理延遲 P50 / P99 (Time Series)

看什麼:推理延遲分位數。

門檻 含義
< 10s (P50) HEALTHY — 正常使用 111
1030s (P50) SLOW — 系統已切至 Gemini
> 30s (P99) DEGRADED — 應觸發 failover

⚠️ BACKLOG 警告ollama_inference_duration_seconds_bucket 尚未在 API 暴露(需在 _check_inference() 加 Histogram.observe())。 面板顯示 "No Data" 是正常的,等 backlog 補完後啟用。


Panel 3 — AI Provider 路由分布 (Pie Chart)

看什麼:過去 5 分鐘各 provider 被選中的請求比例。

分布 意義
ollama / ollama_gcp_a 佔 >90% 正常GCP-A 健康
ollama_gcp_b 佔多數 GCP-A SLOW/DEGRADED/OFFLINE容災到 GCP-B
ollama_local 出現 GCP-A/B 均不可用,容災到 111 local
gemini 佔多數 Ollama provider pool 全部不可用,使用付費備援
全部 nemotron/claude 極端情況,所有主力 provider 失敗

Panel 4 — Failover / Recovery 觸發次數 (Bar Chart)

看什麼:每小時 failover和 recovery的觸發次數。

模式 意義
兩條都接近 0 正常111 穩定運行中
橘色上升後綠色跟上 Auto recovery 正常:切出後又切回
橘色上升,綠色不動 OllamaRecoveryStuck alert,見下方 runbook
橘色持續高頻(>5/h OllamaFailoverFrequent alert111 不穩定

Alert Runbook

OllamaInstanceDown — Ollama 主機離線

觸發條件up{job=~"ollama_gcp_a|ollama_gcp_b|ollama_local|ollama_111"} == 0 持續 2 分鐘。

影響評估

  • 系統應依序切至 GCP-B / 111 local / Gemini查 Panel 3 與 /api/v1/health 確認)
  • 查 Panel 4 是否有 Failover 計數上升

排查步驟

# 步驟 1跑完整只讀診斷先分辨是 110 proxy、111 LAN、或 111 本機服務
bash scripts/ops/ollama111-fallback-proxy-diagnose.sh

# 步驟 2若 110 到 111 是 No route to host / ip neigh INCOMPLETE
# 代表 111 主機或網路不可達;先恢復 111 電源/網路,不要重啟 API。

# 步驟 3若 SSH 到 111 可行,再查本機 Ollama 與 LaunchAgent
ssh ollama-111-gpu 'curl -sS -m 5 http://127.0.0.1:11434/api/tags'
ssh ollama-111-gpu 'launchctl print gui/501/com.momo.ollama111-allow-proxy | head -80'

恢復確認 /api/v1/healthollama_local.status=up,且 scripts/ops/ollama111-fallback-proxy-diagnose.sh 中 110 proxy_11437 回 HTTP 200。


OllamaFailoverFrequent — Failover 頻率過高

觸發條件rate(ollama_failover_triggered_total[1h]) > 5 持續 10 分鐘(每小時超過 5 次切換)。

影響評估

  • 服務本身仍可用Gemini 在接手)
  • 但 Gemini 配額消耗加速,有觸發 GeminiQuotaApproaching 的風險

排查步驟

# 步驟 1確認 111 近況(反覆 OFFLINE/HEALTHY 之間跳動?)
bash scripts/ops/ollama111-fallback-proxy-diagnose.sh

# 步驟 2查 API log 找 failover 原因
kubectl logs -n awoooi-prod deploy/api --since=30m | grep "ollama_failover_triggered"

# 步驟 3查推理延遲是否長期在 SLOW 邊界?)
kubectl logs -n awoooi-prod deploy/api --since=30m | grep "ollama_health_checked"

# 步驟 4如果是 111 本機 Ollama 問題,需依 LaunchAgent runbook 執行維護;不可直接用 Linux systemctl 手順。

OllamaRecoveryStuck — Auto Recovery 停滯

觸發條件ollama_health_status{host="111"} == 1 AND ollama_current_primary_is_ollama == 0 持續 5 分鐘。 111 已 HEALTHY 但路由仍走 Gemini

影響評估

  • API 功能正常Gemini 在服務)
  • 但 Gemini 配額持續消耗111 GPU 資源浪費

排查步驟

# 步驟 1確認 OllamaAutoRecoveryService 是否在運行
kubectl logs -n awoooi-prod deploy/api --since=10m | grep "ollama_auto_recovery"

# 步驟 2查 recovery service 狀態
kubectl logs -n awoooi-prod deploy/api --since=10m | grep -E "ollama_auto_recovery_started|ollama_auto_recovery_stopped|ollama_auto_recovery_loop_error"

# 步驟 3查 current_primary Redis key
kubectl exec -n awoooi-prod deploy/api -- python -c "
import asyncio
from src.core.redis_client import get_redis
async def check():
    r = get_redis()
    val = await r.get('ollama:current_primary')
    print('current_primary:', val)
asyncio.run(check())
"

# 步驟 4如果 recovery service 掛了,重啟 API pod會重新啟動 lifespan
kubectl rollout restart deployment/api -n awoooi-prod
kubectl rollout status deployment/api -n awoooi-prod

GeminiQuotaApproaching — Gemini 配額 >80%

觸發條件gemini_daily_call_count / gemini_daily_quota > 0.8 持續 5 分鐘。

注意gemini_daily_quota 來自 settings.GEMINI_DAILY_QUOTA(預設 1000gemini_daily_call_count 從 Redis key ollama:gemini_daily_count:{YYYY-MM-DD} 讀取並刷新 Gauge。

影響評估

  • 當日 Gemini 配額即將耗盡
  • 耗盡後系統會自動切至 188 CPU-only 備援qwen2.5:7b-instruct速度較慢

行動步驟

# 步驟 1確認當日 Gemini 使用量
kubectl exec -n awoooi-prod deploy/api -- python -c "
import asyncio, datetime
from src.core.redis_client import get_redis
async def check():
    r = get_redis()
    today = datetime.date.today().isoformat()
    val = await r.get(f'ollama:gemini_daily_count:{today}')
    print(f'gemini_daily_count[{today}]:', val)
asyncio.run(check())
"

# 步驟 2確認 111 是否能快速恢復(讓流量切回 Ollama
bash scripts/ops/ollama111-fallback-proxy-diagnose.sh

# 步驟 3如需增加配額修改 settings
# k8s/awoooi-prod/04-configmap.yaml.patch-* 找 GEMINI_DAILY_QUOTA
# 改完後 kubectl apply + rollout restart

# 步驟 4緊急手動重置計數謹慎使用只在確認誤計時才用
# kubectl exec -n awoooi-prod deploy/api -- redis-cli DEL "ollama:gemini_daily_count:$(date +%Y-%m-%d)"

Metric 清單

Metric 類型 狀態 說明
up{job="ollama_gcp_a"} Gauge 現有 Prometheus scrape 存活
up{job="ollama_gcp_b"} Gauge 現有 Prometheus scrape 存活
up{job="ollama_local"} Gauge 現有 Prometheus scrape 存活
ollama_failover_triggered_total Counter P2.3 補入 failover 切換次數labels: from_provider, to_provider
ollama_recovery_triggered_total Counter P2.3 補入 recovery 切回次數labels: from_provider
ollama_health_status{host} Gauge P2.3 補入 健康狀態 1=healthy, 0=not_healthy
ollama_current_primary_is_ollama Gauge P2.3 補入 1=primary 是 ollama, 0=failover 中
ai_router_selected_provider_total Counter P2.3 補入 AI router 選擇次數labels: provider
gemini_daily_call_count Gauge P2.3 補入 今日 Gemini 呼叫次數
gemini_daily_quota Gauge P2.3 補入 Gemini 每日配額
ollama_inference_duration_seconds Histogram BACKLOG 推理延遲分布,需在 _check_inference() 加 observe
post_execution_verification_total Counter BACKLOG Verifier 執行次數,需 auto_repair_service.py 補入
post_execution_verification_failed_total Counter BACKLOG Verifier 失敗次數,需 auto_repair_service.py 補入

Backlog 補完指引

ollama_inference_duration_seconds

apps/api/src/services/ollama_health_monitor.py_check_inference() 方法結尾,加:

from src.core.metrics import OLLAMA_INFERENCE_DURATION  # 需先在 metrics.py 加 Histogram
OLLAMA_INFERENCE_DURATION.labels(host=host_label).observe(latency_ms / 1000)

post_execution_verification_*

apps/api/src/services/auto_repair_service.py 的 verifier 路徑,加 Counter inc()。 需先確認 verifier 執行點grep post_executionverif 找入口)。