Настройка Shadow Deployment для ML-моделей
Shadow deployment (mirror deployment) — стратегия, при которой новая версия модели получает те же запросы, что и production, но её ответы не отдаются пользователям. Цель — протестировать поведение новой модели на реальном трафике без какого-либо риска для пользователей.
Когда применять shadow deployment
- Кардинальная смена архитектуры модели (например, переход от gradient boosting к нейронной сети)
- Новая версия ещё не прошла полное тестирование, но нужно посмотреть на реальные данные
- Проверка latency и resource utilization под реальной нагрузкой
- Валидация пайплайна обработки данных перед новой версией
- Тестирование большой LLM-модели перед заменой меньшей
Архитектура
[User Request]
|
├──→ [Production Model V1] ──→ [Response to User]
|
└──→ [Shadow Model V2] ──→ [Prediction logged, not returned]
|
[Comparison DB]
|
[Metrics Dashboard]
Реализация с Envoy / Istio
Istio mirror:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: ml-inference
spec:
hosts:
- ml-inference
http:
- route:
- destination:
host: ml-inference
subset: v1
weight: 100
mirror:
host: ml-inference
subset: v2-shadow
mirrorPercentage:
value: 100 # Зеркалировать 100% трафика
Nginx mirror:
location /predict {
proxy_pass http://model-v1;
mirror /shadow;
mirror_request_body on;
}
location = /shadow {
internal;
proxy_pass http://model-v2-shadow/predict;
}
Реализация на уровне приложения
Для более гибкого логирования и сравнения — реализация в коде:
import asyncio
import logging
async def predict_with_shadow(request_features):
# Production модель — синхронно
production_result = production_model.predict(request_features)
# Shadow модель — асинхронно, не блокирует ответ
asyncio.create_task(
run_shadow_prediction(request_features, production_result)
)
return production_result
async def run_shadow_prediction(features, production_result):
try:
shadow_result = shadow_model.predict(features)
# Логирование для сравнения
comparison_store.log({
'timestamp': datetime.utcnow(),
'production_score': float(production_result),
'shadow_score': float(shadow_result),
'agreement': abs(production_result - shadow_result) < 0.1,
'features_hash': hash_features(features)
})
except Exception as e:
logging.error(f"Shadow prediction failed: {e}")
# Ошибка в shadow не влияет на production
Метрики сравнения
Agreement rate — процент запросов, где предсказания моделей совпадают (с заданным допуском):
df['agreement'] = abs(df['production'] - df['shadow']) < threshold
agreement_rate = df['agreement'].mean()
# Цель: > 95% agreement для критичных систем
Prediction distribution comparison:
from scipy.stats import ks_2samp
ks_stat, p_value = ks_2samp(df['production'], df['shadow'])
# Если p_value < 0.05 — распределения значимо отличаются
Latency comparison: shadow модель может работать медленнее без последствий для пользователей, но это указывает на будущие latency проблемы при переходе.
Когда переходить с shadow на canary
Рекомендации по переходу:
- Shadow тест прошёл минимум 1 неделю на реальном трафике
- Agreement rate > 95% (или согласованное business решение о допустимом расхождении)
- Latency shadow-модели < SLA (даже с учётом того, что пока она не критична)
- Resource utilization в норме при пиковой нагрузке
- Нет неожиданных ошибок в логах shadow-сервиса
Shadow deployment — наиболее безопасная стратегия тестирования, особенно для систем, где цена ошибки высока: финансовые решения, медицинская диагностика, системы безопасности.







