
1. 머신러닝 배포 전략의 진화: 왜 트래픽 라우팅이 중요한가?
머신러닝(ML) 모델은 정적인 소프트웨어와 달리 데이터의 변화에 민감하게 반응합니다. 새로운 모델을 배포할 때 가장 큰 리스크는 오프라인 검증(Offline Validation) 성능이 우수하더라도 실제 운영 환경(Online)에서는 예상치 못한 편향이나 성능 저하가 발생할 수 있다는 점입니다. 이를 해결하기 위해 A/B Testing과 Canary Deployment는 현대적인 MLOps 아키텍처의 필수 요소가 되었습니다. 하지만 단순히 트래픽을 나누는 것만으로는 부족합니다. 사용자의 경험을 해치지 않으면서 모델의 성능을 통계적으로 유의미하게 비교하기 위해서는 정교한 트래픽 라우팅(Traffic Routing) 기준이 필요합니다. 본 가이드에서는 파이썬 기반 인프라에서 적용 가능한 구체적인 라우팅 설계 방법과 실무적 해결책을 제시합니다.
2. A/B Testing vs Canary Deployment: 목적과 라우팅 메커니즘의 차이
두 전략은 트래픽을 분할한다는 공통점이 있지만, 그 목적과 대상, 그리고 라우팅의 기준이 되는 데이터에서 큰 차이를 보입니다.
| 비교 항목 | A/B Testing (A/B 테스트) | Canary Deployment (카나리 배포) |
|---|---|---|
| 주요 목적 | 두 모델 간 비즈니스 지표(예: 클릭률) 비교 | 신규 모델의 안정성 검증 및 리스크 최소화 |
| 라우팅 기준 | 사용자 식별자(User ID), 쿠키(Cookie) 기반 | 트래픽 비율(%), 지리적 위치, 인프라 부하 |
| 테스트 기간 | 통계적 유의미성 확보까지 (장기적) | 안전성이 확인될 때까지 (단기적) |
| 성공 판단 지표 | 전환율(CVR), 평균 주문 금액(AOV) 등 | 에러율, 응답 속도(Latency), 시스템 자원 점유 |
| 라우팅 복잡도 | 세션 유지(Stickiness)가 매우 중요함 | 점진적 트래픽 증가가 중요함 |
3. ML 모델 라우팅의 5가지 핵심 기준 (KPI 및 실무 전략)
실제 프로덕션 환경에서 트래픽을 분배할 때 엔지니어가 반드시 고려해야 할 5가지 라우팅 기준은 다음과 같습니다.
- Deterministic Hashing (결정론적 해싱): 사용자 ID를 해싱하여 특정 버전에 할당함으로써 동일 사용자가 항상 같은 모델의 결과를 보게 하는 '세션 고정'이 필수입니다.
- User Attribute-based (사용자 속성 기반): 특정 지역, 특정 디바이스, 또는 신규 회원에게만 신규 모델을 노출하여 위험군을 한정합니다.
- Time-based Scheduling (시간 기반): 트래픽이 적은 야간 시간대에 카나리 배포를 시작하여 모니터링을 강화합니다.
- Infrastructure Resource-based (자원 기반): 신규 모델의 메모리나 GPU 점유율이 일정 임계치를 넘으면 즉시 트래픽을 차단합니다.
- Experimental Bucketing (실험군 버킷화): 통계적 분석을 위해 전체 사용자를 일정한 비율의 버킷(Bucket)으로 나누어 독립적인 실험 환경을 보장합니다.
4. 실무 적용을 위한 7가지 Python 및 인프라 구현 예제
다음은 파이썬과 클라우드 네이티브 환경에서 트래픽 라우팅을 구현할 때 즉시 활용 가능한 코드 샘플입니다.
예제 1: Python 해시 함수를 이용한 A/B 테스트 그룹 할당
User ID를 바탕으로 일관된 모델 버전을 할당하는 가장 기본적인 방법입니다.
import hashlib
def get_model_version(user_id, salt="ml_experiment_v1"):
# User ID와 Salt를 조합하여 해시값 생성
combined = f"{user_id}:{salt}".encode('utf-8')
hash_val = int(hashlib.md5(combined).hexdigest(), 16)
# 트래픽을 50:50으로 분할
return "model_b" if (hash_val % 100) < 50 else "model_a"
# 테스트
print(get_model_version("user_123"))
예제 2: FastAPI와 Header 기반의 트래픽 라우팅 미들웨어
HTTP 헤더에 따라 특정 모델 인스턴스로 요청을 전달하는 게이트웨이 로직입니다.
from fastapi import FastAPI, Request
import httpx
app = FastAPI()
MODEL_A_URL = "http://model-a-service:8000/predict"
MODEL_B_URL = "http://model-b-service:8000/predict"
@app.post("/route")
async def route_request(request: Request):
user_group = request.headers.get("X-User-Group", "control")
target_url = MODEL_B_URL if user_group == "canary" else MODEL_A_URL
async with httpx.AsyncClient() as client:
response = await client.post(target_url, json=await request.json())
return response.json()
예제 3: Redis를 활용한 동적 Canary 트래픽 비율 조정
서비스 중단 없이 실시간으로 카나리 트래픽 비율을 변경하는 방법입니다.
import redis
import random
r = redis.Redis(host='localhost', port=6379, db=0)
def should_use_canary():
# Redis에서 현재 설정된 카나리 비율(0~100)을 가져옴
canary_ratio = int(r.get("canary_weight") or 5)
return random.randint(1, 100) <= canary_ratio
if should_use_canary():
print("Routing to Canary Model")
else:
print("Routing to Stable Model")
예제 4: Istio VirtualService를 이용한 가중치 기반 라우팅 (YAML)
쿠버네티스 환경에서 인프라 레벨의 트래픽 분할 설정 예시입니다.
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: ml-model-route
spec:
hosts:
- ml-service
http:
- route:
- destination:
host: ml-service
subset: v1
weight: 90
- destination:
host: ml-service
subset: v2
weight: 10
예제 5: Python SDK를 활용한 AWS SageMaker Canary 배포 자동화
import boto3
sm = boto3.client('sagemaker')
def update_canary_weight(endpoint_name, variant_weights):
response = sm.update_endpoint_weights_and_capacities(
EndpointName=endpoint_name,
DesiredWeightAndCapacities=[
{'VariantName': 'StableVariant', 'DesiredWeight': variant_weights['stable']},
{'VariantName': 'CanaryVariant', 'DesiredWeight': variant_weights['canary']}
]
)
return response
예제 6: Pandas를 이용한 A/B 테스트 결과의 통계적 유의성 검증(T-Test)
라우팅된 결과 데이터를 바탕으로 어떤 모델이 실제로 우수한지 판단합니다.
from scipy import stats
import pandas as pd
def analyze_ab_test(model_a_scores, model_b_scores):
t_stat, p_val = stats.ttest_ind(model_a_scores, model_b_scores)
if p_val < 0.05:
return f"Statistically Significant: Model {'B' if t_stat < 0 else 'A'} wins!"
return "Not Significant"
예제 7: 유저 세그먼트별 조건부 라우팅 로직 (Python Logic)
def segment_routing_logic(user_profile):
# 프리미엄 유저에게는 검증된 모델만 제공
if user_profile['membership'] == 'premium':
return "stable_v1"
# 신규 기능 테스트 그룹 확인
if user_profile['region'] == 'US-EAST' and user_profile['age'] < 30:
return "experimental_v2"
return "stable_v1"
5. 해결 전략: 라우팅 시 발생할 수 있는 문제와 대응 방안
트래픽 라우팅을 적용할 때 가장 흔히 발생하는 해결 과제들은 다음과 같습니다.
- 데이터 불균형 문제: 라우팅 알고리즘의 결함으로 한쪽 그룹에 데이터가 쏠리는 현상. 이를 위해 정기적인 로그 감사(Audit)가 필요합니다.
- Cold Start 현상: 신규 모델(Canary)이 로드될 때 발생하는 초기 지연 시간. 사전 워밍업(Warm-up) 요청을 통해 해결합니다.
- 훈련-추론 왜곡(Training-Serving Skew): 운영 환경의 라우팅 기준이 학습 데이터의 분포와 다를 때 성능이 급락합니다. 이를 위해 동일한 해싱 로직을 전처리 단계에도 적용해야 합니다.