Skip to main content

Training-Serving Skew 방지 메커니즘

💡 Training-Serving Skew(학습-서빙 불일치) 란 모델 학습 시 사용한 피처와 프로덕션 서빙 시 사용하는 피처가 다르게 계산되는 문제입니다. 이 불일치는 모델 성능을 심각하게 저하시킬 수 있습니다.

Skew가 발생하는 일반적인 원인

원인설명예시
계산 로직 불일치학습 시 Python, 서빙 시 Java로 같은 로직을 다르게 구현평균 계산에서 NULL 처리 방식 차이
데이터 소스 차이학습은 배치 테이블, 서빙은 실시간 스트림집계 기간 차이로 값이 다름
피처 버전 불일치학습 시 v1 피처, 서빙 시 v2 피처새 피처 추가 후 모델 재학습 안 함
타이밍 차이학습은 일 단위 배치, 서빙은 실시간당일 데이터 포함 여부 차이

Databricks의 Skew 방지 아키텍처

단계학습 시서빙 시
입력labels_df (customer_id, is_churned)추론 요청 (customer_id)
피처 조회FeatureLookup → Feature Table (Delta)동일한 피처 정의 자동 적용
결과training_df → 모델 학습 → 모델 등록 (피처 의존성 자동 기록)Online Table에서 피처 조회 → 모델 추론 → 예측 결과 반환
핵심: 학습과 서빙에서 동일한 Feature Table 정의 를 사용하므로 Training-Serving Skew가 방지됩니다.
방지 메커니즘설명
단일 피처 소스학습과 서빙 모두 같은 Feature Table에서 피처를 조회합니다
자동 피처 기록모델 등록 시 어떤 Feature Table의 어떤 컬럼을 사용했는지 자동 기록됩니다
Online Table 동기화Feature Table(오프라인) → Online Table(온라인)이 자동 동기화됩니다
서빙 시 자동 조회Model Serving이 모델에 기록된 피처 의존성을 보고, Online Table에서 자동으로 피처를 조회합니다

Point-in-Time 정확성 보장 원리

Point-in-Time Lookup의 내부 동작을 더 상세히 이해하면, 시계열 피처 설계에서 실수를 방지할 수 있습니다.

동작 원리

labels_df:
  customer_id | event_timestamp | is_churned
  C001        | 2025-03-15      | True
  C001        | 2025-01-10      | False

Feature Table (customer_features):
  customer_id | feature_timestamp | total_orders | lifetime_revenue
  C001        | 2025-01-01       | 10           | 500,000
  C001        | 2025-02-01       | 15           | 750,000
  C001        | 2025-03-01       | 18           | 900,000

Point-in-Time Lookup 결과:
  C001 | 2025-03-15 → total_orders=18, lifetime_revenue=900,000  (3월 1일 기준)
  C001 | 2025-01-10 → total_orders=10, lifetime_revenue=500,000  (1월 1일 기준)
  ← 각 이벤트 시점 기준으로 "과거의 피처 값"만 사용
⚠️ AsOf Join: Point-in-Time Lookup은 내부적으로 AsOf Join(가장 가까운 과거 시점 매칭)을 수행합니다. event_timestamp보다 같거나 이전인 feature_timestamp 중 가장 최신 값을 선택합니다.

timestamp_lookup_key 설계 주의사항

패턴권장 여부설명
일별 스냅샷✅ 권장매일 피처를 계산하여 타임스탬프와 함께 저장
이벤트 기반 업데이트✅ 좋음주문, 결제 등 이벤트 발생 시마다 피처 업데이트
최종 값만 저장❌ 비권장과거 시점 조회가 불가능하여 Point-in-Time 의미 없음
불규칙 업데이트⚠️ 주의업데이트 간격이 불규칙하면 오래된 피처가 사용될 수 있음

Feature Governance (UC 통합)

Feature Table은 Unity Catalog의 Delta 테이블이므로, 모든 UC 거버넌스 기능이 적용됩니다.

피처 수준 거버넌스

-- Feature Table 접근 권한 관리
GRANT SELECT ON TABLE catalog.ml.customer_features TO `ml_engineers`;
GRANT SELECT, MODIFY ON TABLE catalog.ml.customer_features TO `feature_team`;

-- 피처 태그 지정
ALTER TABLE catalog.ml.customer_features
SET TAGS ('domain' = 'customer', 'pii' = 'false', 'freshness_sla' = 'daily');

-- 컬럼별 태그 (민감 정보 표시)
ALTER TABLE catalog.ml.customer_features
ALTER COLUMN email SET TAGS ('pii' = 'true');

-- 피처 리니지 확인
SELECT * FROM system.lineage.table_lineage
WHERE target_table_full_name = 'catalog.ml.customer_features';

피처 검색 (Discovery)

# Unity Catalog에서 피처 테이블 검색
from databricks.sdk import WorkspaceClient
w = WorkspaceClient()

# 태그 기반 검색: 'customer' 도메인의 피처 테이블 찾기
tables = w.tables.list(catalog_name="catalog", schema_name="ml")
for t in tables:
    if t.table_type == "MANAGED" and "feature" in t.name:
        print(f"{t.full_name}: {t.comment}")

Feature Freshness 모니터링

피처가 오래되면(stale), 모델 성능이 저하됩니다. 피처 신선도(Freshness)를 모니터링하는 것이 중요합니다.

Freshness 모니터링 패턴

# 피처 테이블의 마지막 업데이트 시간 확인
last_update = spark.sql("""
    DESCRIBE HISTORY catalog.ml.customer_features
    LIMIT 1
""").select("timestamp").collect()[0][0]

from datetime import datetime, timedelta
staleness = datetime.now() - last_update

if staleness > timedelta(hours=24):
    # Alert 발생: 피처가 24시간 이상 업데이트되지 않음
    print(f"⚠️ Feature staleness alert: {staleness}")

Databricks Lakehouse Monitoring 연동

-- Feature Table에 모니터 설정
CREATE MONITOR catalog.ml.customer_features
WITH (
  SCHEDULE = CRON '0 0 * * *',  -- 매일 체크
  BASELINE_TABLE = 'catalog.ml.customer_features_baseline'
);

-- 모니터링 결과 확인: 데이터 드리프트 감지
SELECT * FROM catalog.ml.customer_features_profile_metrics
WHERE log_type = 'DATA_DRIFT'
  AND drift_detected = true;

대규모 Feature Table 설계 패턴

Wide vs Narrow 테이블 전략

전략구조적합한 경우
Wide Table하나의 테이블에 모든 피처 (수백 컬럼)단일 엔터티(고객, 상품)의 피처가 함께 사용되는 경우
Narrow Tables도메인별로 분리된 여러 테이블팀별로 독립적으로 피처를 관리하는 경우
Hybrid핵심 피처는 Wide, 전문 피처는 Narrow대규모 조직에서 권장

Wide Table 예시

# 고객의 모든 피처를 하나의 테이블에
fe.create_table(
    name="catalog.ml.customer_features_wide",
    primary_keys=["customer_id"],
    timestamp_keys=["feature_date"],  # Point-in-Time용
    df=wide_features_df,  # 200+ 컬럼
    description="고객 통합 피처 테이블 (행동, 인구통계, 거래, 상호작용 피처 포함)"
)

Narrow Tables + 다중 FeatureLookup

# 여러 도메인별 Feature Table에서 조합
training_set = fe.create_training_set(
    df=labels_df,
    feature_lookups=[
        FeatureLookup(table_name="catalog.ml.customer_demographics", lookup_key="customer_id"),
        FeatureLookup(table_name="catalog.ml.customer_transactions", lookup_key="customer_id",
                      timestamp_lookup_key="event_date"),
        FeatureLookup(table_name="catalog.ml.customer_interactions", lookup_key="customer_id",
                      timestamp_lookup_key="event_date"),
        FeatureLookup(table_name="catalog.ml.product_features", lookup_key="product_id"),
    ],
    label="is_churned"
)

대용량 Feature Table 최적화

최적화설명효과
Liquid ClusteringCLUSTER BY (customer_id)로 Primary Key 기준 클러스터링Lookup 성능 5~10배 향상
Z-ORDEROPTIMIZE ... ZORDER BY (customer_id)범위 스캔 최적화
파티션 전략일별/월별 feature_date 파티션Point-in-Time 쿼리 시 불필요한 스캔 방지
Auto CompactionDelta Lake 자동 파일 병합소규모 파일 문제 방지
Column PruningFeatureLookup에서 feature_names 명시필요한 컬럼만 읽어서 I/O 절감
# Liquid Clustering 적용
spark.sql("""
    ALTER TABLE catalog.ml.customer_features
    CLUSTER BY (customer_id)
""")

# 특정 피처만 선택 (Column Pruning)
FeatureLookup(
    table_name="catalog.ml.customer_features",
    lookup_key="customer_id",
    feature_names=["total_orders", "lifetime_revenue", "avg_order_value"]  # 필요한 것만
)

Online Table과 실시간 서빙 심화

Online Table 동기화 모드

모드지연 시간비용적합한 경우
Snapshot분~시간 (스케줄)낮음피처가 자주 변하지 않는 경우 (인구통계 등)
Triggered분 단위중간피처 업데이트 직후 동기화 필요 시
Continuous (CDC)초 단위높음실시간 피처가 필요한 경우 (실시간 거래 등)
# Online Table 생성 (Continuous 동기화)
w.online_tables.create(
    name="catalog.ml.customer_features_online",
    spec={
        "source_table_full_name": "catalog.ml.customer_features",
        "primary_key_columns": ["customer_id"],
        "run_continuously": {
            "triggered": False  # True면 Triggered 모드
        }
    }
)
⚠️ 비용 주의: Continuous 모드의 Online Table은 항상 실행 상태이므로 비용이 지속적으로 발생합니다. 실시간성이 정말 필요한 피처에만 적용하고, 나머지는 Snapshot이나 Triggered 모드를 사용하세요.

정리

핵심 개념설명
FeatureML 모델의 입력 데이터 속성입니다
Feature TableUnity Catalog에서 피처를 중앙 관리하는 테이블입니다
FeatureLookup학습 데이터에 피처를 자동으로 결합합니다
Point-in-Time시간 기준으로 피처를 조회하여 데이터 유출을 방지합니다
Training-Serving Skew학습과 서빙의 피처 불일치 문제이며, Feature Table로 방지합니다
Feature GovernanceUC 권한, 태그, 리니지로 피처를 거버넌스합니다
Feature Freshness피처의 신선도를 모니터링하여 모델 성능 저하를 방지합니다
Online Table실시간 서빙에 최적화된 피처 저장소입니다

참고 링크