Skip to main content

트래픽 분할 및 A/B 테스트

하나의 엔드포인트에 여러 모델 버전을 동시에 배포하고, 트래픽 비율을 조절하여 A/B 테스트 를 수행할 수 있습니다.
구성 요소트래픽 비율설명
클라이언트 요청100%엔드포인트(fraud-detection)로 전송됩니다
모델 v3 (현재 프로덕션)80%현재 안정된 프로덕션 모델입니다
모델 v4 (챌린저)20%성능을 검증 중인 새 버전 모델입니다
응답-두 모델의 응답이 클라이언트에 반환됩니다
# 트래픽 분할 설정
client = mlflow.deployments.get_deploy_client("databricks")

client.update_endpoint(
    endpoint="fraud-detection-v2",
    config={
        "served_entities": [
            {
                "entity_name": "catalog.schema.fraud_detection_custom",
                "entity_version": "3",
                "workload_size": "Small",
                "scale_to_zero_enabled": False
            },
            {
                "entity_name": "catalog.schema.fraud_detection_custom",
                "entity_version": "4",
                "workload_size": "Small",
                "scale_to_zero_enabled": False
            }
        ],
        "traffic_config": {
            "routes": [
                {"served_model_name": "fraud_detection_custom-3", "traffic_percentage": 80},
                {"served_model_name": "fraud_detection_custom-4", "traffic_percentage": 20}
            ]
        }
    }
)
블루-그린 배포: 새 모델 버전을 100% 트래픽으로 전환하면서도 이전 버전을 유지하는 방식입니다. 문제 발생 시 즉시 이전 버전으로 롤백할 수 있습니다.

모니터링 (Monitoring)

Inference Table (추론 로그 테이블)

Inference Table 은 엔드포인트의 모든 요청/응답을 Unity Catalog 테이블에 자동으로 저장합니다. 모델 드리프트 감지, 디버깅, 감사 로그 목적으로 활용합니다.
# Inference Table 활성화 (엔드포인트 생성 또는 업데이트 시)
config = {
    "served_entities": [...],
    "auto_capture_config": {
        "catalog_name": "main",
        "schema_name": "serving_logs",
        "table_name_prefix": "fraud_endpoint",   # 테이블명: fraud_endpoint_payload
        "enabled": True
    }
}
-- Inference Table 쿼리 예시
-- 테이블명: {catalog}.{schema}.{prefix}_payload
SELECT
    timestamp,
    request_id,
    databricks_request_id,
    -- 요청 데이터 파싱
    request:dataframe_records[0].amount::double AS amount,
    request:dataframe_records[0].merchant_category::string AS merchant_category,
    -- 응답 데이터 파싱
    response:predictions[0].fraud_probability::double AS fraud_probability,
    response:predictions[0].is_fraud::int AS is_fraud,
    -- 메타데이터
    status_code,
    execution_duration_ms
FROM main.serving_logs.fraud_endpoint_payload
WHERE timestamp >= current_date() - interval 7 days
ORDER BY timestamp DESC;
# Python에서 Inference Table 조회
from databricks.connect import DatabricksSession

spark = DatabricksSession.builder.getOrCreate()

# 최근 1시간 요청 분석
df = spark.sql("""
    SELECT
        date_trunc('minute', timestamp) AS minute,
        count(*) AS request_count,
        avg(execution_duration_ms) AS avg_latency_ms,
        percentile_approx(execution_duration_ms, 0.95) AS p95_latency_ms,
        sum(CASE WHEN status_code != 200 THEN 1 ELSE 0 END) AS error_count
    FROM main.serving_logs.fraud_endpoint_payload
    WHERE timestamp >= now() - interval 1 hour
    GROUP BY 1
    ORDER BY 1
""")
df.display()

엔드포인트 메트릭 확인

from databricks.sdk import WorkspaceClient

w = WorkspaceClient()

# 엔드포인트 상태 조회
endpoint = w.serving_endpoints.get(name="fraud-detection-v2")
print(f"State: {endpoint.state.ready}")
print(f"Config update: {endpoint.state.config_update}")

# 이벤트 로그 조회 (디버깅용)
for event in w.serving_endpoints.list_serving_endpoint_events(name="fraud-detection-v2"):
    print(f"[{event.timestamp}] {event.type}: {event.message}")

콜드 스타트 최적화

콜드 스타트 (Cold Start)scale_to_zero_enabled=True 설정 시 트래픽이 없다가 첫 요청이 들어올 때 컨테이너를 다시 시작하는 지연 시간입니다. 일반적으로 30초~5분이 소요됩니다.
전략방법트레이드오프
Scale-to-zero 비활성화scale_to_zero_enabled=False비용 증가, 콜드 스타트 없음
Provisioned Concurrency최소 인스턴스 수 설정비용 증가, 항상 warm 상태
모델 경량화ONNX 변환, 양자화 (Quantization)로드 시간 단축
의존성 최소화불필요한 패키지 제거컨테이너 빌드/로드 속도 향상
# Provisioned Concurrency 설정 (최소 인스턴스 보장)
endpoint = client.create_endpoint(
    name="fraud-detection-prod",
    config={
        "served_entities": [{
            "entity_name": "catalog.schema.fraud_detection_custom",
            "entity_version": "3",
            "workload_size": "Small",
            "scale_to_zero_enabled": False,     # 항상 최소 1개 인스턴스 유지
            "workload_type": "CPU"
        }]
    }
)
load_context() 최적화: 무거운 초기화(모델 로드, 토크나이저 초기화 등)는 반드시 load_context()에서 수행하고 predict()에서는 수행하지 마십시오. load_context()는 인스턴스 시작 시 한 번만 실행되지만, predict()는 매 요청마다 실행됩니다.

비용 관리

커스텀 모델 서빙은 인스턴스 가동 시간 기준으로 과금됩니다. Foundation Model API의 토큰 기반 과금과 다른 비용 구조를 갖습니다.
비용 요소설명절감 방법
인스턴스 크기Small < Medium < Large 순으로 과금실제 트래픽에 맞는 크기 선택
Scale-to-zero트래픽 없을 때 인스턴스 종료개발/비업무 시간에 활성화
GPU 비용CPU 대비 5~10배 비용실제 GPU 필요 여부 사전 검증
Inference Table 저장Delta Lake 스토리지 비용보존 기간 설정 (TBLPROPERTIES)
-- Inference Table 데이터 보존 기간 설정 (90일 후 자동 삭제)
ALTER TABLE main.serving_logs.fraud_endpoint_payload
SET TBLPROPERTIES (
    'delta.deletedFileRetentionDuration' = 'interval 90 days'
);
# 비용 절감: 개발 환경은 scale_to_zero 활성화, 프로덕션은 비활성화
def create_endpoint_by_env(env: str, model_name: str, version: str):
    is_prod = env == "production"
    return client.create_endpoint(
        name=f"fraud-detection-{env}",
        config={
            "served_entities": [{
                "entity_name": model_name,
                "entity_version": version,
                "workload_size": "Medium" if is_prod else "Small",
                "scale_to_zero_enabled": not is_prod,
                "workload_type": "CPU"
            }]
        }
    )

실습: 모델 서빙 엔드포인트 생성 및 호출

엔드포인트 호출 방법

import requests
import json

# 방법 1: requests 라이브러리
workspace_url = "https://<workspace-url>"
token = dbutils.notebook.entry_point.getDbutils().notebook().getContext().apiToken().get()

url = f"{workspace_url}/serving-endpoints/fraud-detection-v2/invocations"
headers = {
    "Authorization": f"Bearer {token}",
    "Content-Type": "application/json"
}

# DataFrame 레코드 형식
payload = {
    "dataframe_records": [
        {"amount": 50000, "merchant_category": "online_retail", "hour": 3, "is_international": 1},
        {"amount": 25, "merchant_category": "grocery", "hour": 12, "is_international": 0}
    ]
}

response = requests.post(url, json=payload, headers=headers)
predictions = response.json()
print(json.dumps(predictions, indent=2))
# 방법 2: Databricks SDK
from databricks.sdk import WorkspaceClient

w = WorkspaceClient()

response = w.serving_endpoints.query(
    name="fraud-detection-v2",
    dataframe_records=[
        {"amount": 50000, "merchant_category": "online_retail", "hour": 3, "is_international": 1}
    ]
)
print(response.predictions)
# 방법 3: MLflow Deployments Client
client = mlflow.deployments.get_deploy_client("databricks")

response = client.predict(
    endpoint="fraud-detection-v2",
    inputs={
        "dataframe_records": [
            {"amount": 50000, "merchant_category": "online_retail", "hour": 3}
        ]
    }
)
print(response)

베스트 프랙티스와 흔한 실수

베스트 프랙티스

항목권장 사항
시그니처 필수 정의infer_signature()로 항상 입출력 스키마를 명시합니다
의존성 버전 고정scikit-learn==1.4.0처럼 정확한 버전을 pip_requirements에 명시합니다
load_context 최적화모델 로드 등 무거운 작업은 load_context()에서 처리합니다
input_example 제공log_model() 시 실제 샘플 데이터를 input_example로 제공합니다
Inference Table 활성화프로덕션에서는 항상 auto_capture_config를 활성화합니다
환경별 scale_to_zero개발은 True, 프로덕션은 False로 설정합니다

흔한 실수

실수증상해결 방법
의존성 미명시ModuleNotFoundError 발생pip_requirements에 모든 패키지 버전 명시
모델 크기 초과엔드포인트 PENDING 상태에서 멈춤커스텀 모델 크기는 일반적으로 수 GB 이하 권장
predict()에서 무거운 로드요청마다 수 초 지연초기화 로직을 load_context()로 이동
시그니처 불일치400 Bad Request 오류요청 형식을 input_example과 동일하게 맞춤
타임아웃 미고려기본 타임아웃(60초) 초과 오류모델 최적화 또는 비동기 처리 패턴 도입
GPU 없이 GPU 모델 실행CUDA 오류 발생workload_type="GPU_SMALL" 이상으로 설정
scale_to_zero + 저레이턴시첫 요청 30초~수 분 지연프로덕션에서는 scale_to_zero_enabled=False

트러블슈팅

자주 발생하는 문제와 해결 방법

증상원인해결 방법
엔드포인트가 PENDING 상태에서 멈춤모델 로드 실패 또는 의존성 문제엔드포인트 이벤트 로그 확인. conda_env에 정확한 패키지 버전 명시
ModuleNotFoundError서빙 환경에 필요한 패키지 미설치pip_requirements 또는 conda_env에 모든 의존성 추가
입력 스키마 불일치요청 데이터의 컬럼명/타입이 모델 시그니처와 다름input_example과 동일한 형식으로 요청. 모델 시그니처 확인
Scale-to-zero 후 첫 요청 느림Cold Start (컨테이너 부팅 시간)프로덕션에서는 scale_to_zero_enabled=False 사용
메모리 부족 (OOM)모델 크기 대비 워크로드 크기가 작음workload_size를 Medium/Large로 변경
GPU 할당 실패GPU 리소스 부족다른 GPU 타입 시도 또는 워크스페이스 관리자에 문의

엔드포인트 상태 확인

from databricks.sdk import WorkspaceClient

w = WorkspaceClient()

# 엔드포인트 상태 조회
endpoint = w.serving_endpoints.get(name="fraud-detection-v2")
print(f"State: {endpoint.state.ready}")
print(f"Config update: {endpoint.state.config_update}")

# 이벤트 로그 조회 (디버깅용)
for event in w.serving_endpoints.list_serving_endpoint_events(name="fraud-detection-v2"):
    print(f"[{event.timestamp}] {event.type}: {event.message}")
프로덕션 배포 체크리스트:
  • 모델 시그니처(input/output schema)가 올바른지 확인
  • pip_requirements에 모든 의존성과 정확한 버전을 명시
  • Scale-to-zero 비활성화 (지연 시간 민감한 경우)
  • Inference Table을 활성화하여 요청/응답 로깅
  • 엔드포인트 모니터링 알림 설정

정리

항목핵심 포인트
커스텀 vs FMAPI파인튜닝 모델, 전후처리, 데이터 거버넌스가 필요하면 커스텀 배포를 선택합니다
모델 시그니처infer_signature()로 입출력 스키마를 명시하여 런타임 오류를 사전 방지합니다
커스텀 PyFuncPythonModel을 상속하여 전처리/후처리/앙상블 등 자유로운 추론 로직을 구현합니다
엔드포인트 생성SDK, REST API, UI 세 가지 방법으로 생성할 수 있습니다
트래픽 분할A/B 테스트와 블루-그린 배포로 안전하게 모델을 교체합니다
GPU 서빙workload_type으로 T4/A10G/A100 등 GPU를 선택합니다
콜드 스타트프로덕션에서는 scale_to_zero_enabled=False로 지연 시간을 예측 가능하게 유지합니다
모니터링Inference Table에서 요청/응답을 SQL로 분석하고, 레이턴시와 에러율을 추적합니다
비용 관리환경별 workload_size와 scale_to_zero 설정으로 불필요한 비용을 절감합니다
의존성 관리conda_env 또는 pip_requirements에 정확한 버전을 명시하는 것이 핵심입니다

참고 링크