> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sifi.life/llms.txt
> Use this file to discover all available pages before exploring further.

# 모니터링 핵심 메트릭과 Inference Table

> 이 문서는 **[머신러닝](/training/09-machine-learning/overview)** 섹션의 일부입니다.

## 왜 모니터링이 중요한가요?

모델을 학습하고 배포하는 것은 ML 라이프사이클의 **시작** 에 불과합니다. 프로덕션 환경에서 모델은 다양한 이유로 성능이 저하될 수 있습니다.

* **데이터 드리프트(Data Drift)**: 실제 입력 데이터의 분포가 학습 데이터와 달라집니다
* **모델 성능 저하**: 시간이 지나면서 예측 정확도가 떨어집니다
* **인프라 장애**: 지연 시간 증가, 에러율 상승, 리소스 부족 등이 발생합니다
* **비용 폭증**: 예상치 못한 트래픽 증가로 비용이 급격히 올라갑니다

> 💡 **MLOps의 핵심 원칙**: "모니터링 없는 모델 배포는, 계기판 없이 비행기를 조종하는 것과 같습니다." 모니터링은 모델의 건강 상태를 지속적으로 확인하고, 문제를 조기에 발견하여 대응할 수 있게 해줍니다.

### 프로덕션 ML 장애 패턴과 SLA 관리

실제 프로덕션 환경에서 발생하는 대표적인 장애 패턴과 SLA(Service Level Agreement) 관리 방법을 이해하는 것이 중요합니다.

**대표적인 프로덕션 장애 패턴:**

| 장애 유형                      | 발생 시기                | 탐지 난이도          | 영향 범위      |
| -------------------------- | -------------------- | --------------- | ---------- |
| **콜드 스타트 지연**              | Scale-to-Zero 후 첫 요청 | 쉬움 (즉시 감지)      | 개별 요청      |
| **데이터 스키마 변경**             | 업스트림 파이프라인 배포 후      | 중간 (에러율 급증)     | 전체 서비스     |
| **개념 드리프트(Concept Drift)** | 수주\~수개월 경과 후         | 어려움 (점진적 성능 저하) | 비즈니스 전체    |
| **메모리 누수**                 | 오랜 운영 후              | 중간 (지연 시간 증가)   | 서버 전체      |
| **토큰 폭발(Token Explosion)** | 사용자 프롬프트 변화          | 쉬움 (비용 급증)      | 비용 및 지연 시간 |
| **모델 버전 불일치**              | A/B 테스트 중 배포 오류      | 어려움 (부분적 오류)    | 일부 사용자     |

**SLA 기준값 (일반 권장사항):**

| 메트릭                 | 경고 임계값       | 위험 임계값       | SLA 예시               |
| ------------------- | ------------ | ------------ | -------------------- |
| **P99 지연시간**        | > 500ms      | > 1,000ms    | 99%의 요청을 500ms 이내 처리 |
| **에러율(Error Rate)** | > 1%         | > 5%         | 99.9% 가용성 보장         |
| **처리량(Throughput)** | \< 계획 대비 80% | \< 계획 대비 50% | 최대 1,000 RPS 처리      |
| **드리프트 PSI**        | > 0.1        | > 0.2        | 월간 재학습 트리거           |

> ⚠️ **중요**: SLA 임계값은 비즈니스 요구사항에 따라 조정해야 합니다. 추천 시스템과 실시간 사기 탐지는 요구되는 지연시간 SLA가 크게 다릅니다.

***

## 모니터링 계층 구조

효과적인 모니터링은 세 가지 계층으로 나누어 접근합니다. 인프라/서빙 → 모델 성능 → 비즈니스 메트릭 순으로 계층적으로 모니터링합니다.

| 계층            | 주요 메트릭                                               | 도구                                     |
| ------------- | ---------------------------------------------------- | -------------------------------------- |
| **1. 인프라/서빙** | QPS, 지연시간(P50/P95/P99), 에러율, GPU/CPU 사용률, 비용(DBU/토큰) | Serving UI, 시스템 테이블                    |
| **2. 모델 성능**  | 예측 정확도, 데이터 드리프트, 피처 분포 변화                           | Inference Table + Lakehouse Monitoring |
| **3. 비즈니스**   | 전환율, 매출 영향, 사용자 만족도                                  | 커스텀 대시보드, AI/BI                        |

***

## 핵심 메트릭 심화

### 지연 시간 Percentile (Latency Percentiles)

단순 평균(Average) 지연 시간은 이상치(Outlier)에 민감하여 실제 사용자 경험을 왜곡할 수 있습니다. 반드시 **Percentile 기반 메트릭** 을 사용해야 합니다.

| 메트릭                   | 의미                      | 활용                         |
| --------------------- | ----------------------- | -------------------------- |
| **P50 (중앙값, Median)** | 요청의 50%가 이 시간 이내에 처리됨   | "보통 사용자"의 경험               |
| **P95**               | 요청의 95%가 이 시간 이내에 처리됨   | 대부분 사용자의 경험                |
| **P99**               | 요청의 99%가 이 시간 이내에 처리됨   | 느린 사용자의 경험, SLA 기준으로 주로 사용 |
| **P99.9**             | 요청의 99.9%가 이 시간 이내에 처리됨 | 매우 엄격한 SLA (금융, 의료 등)      |

> 💡 **P99가 중요한 이유**: P50이 100ms이더라도 P99가 5,000ms이면, 100명 중 1명은 5초를 기다립니다. 높은 트래픽에서는 이 1%가 수백 명에 달할 수 있습니다.

```sql theme={null}
-- system 테이블에서 Percentile 메트릭 계산
SELECT
    endpoint_name,
    DATE(request_time) AS day,
    COUNT(*) AS total_requests,
    ROUND(PERCENTILE_CONT(0.50) WITHIN GROUP (ORDER BY execution_time_ms), 1) AS p50_ms,
    ROUND(PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY execution_time_ms), 1) AS p95_ms,
    ROUND(PERCENTILE_CONT(0.99) WITHIN GROUP (ORDER BY execution_time_ms), 1) AS p99_ms,
    ROUND(PERCENTILE_CONT(0.999) WITHIN GROUP (ORDER BY execution_time_ms), 1) AS p999_ms,
    ROUND(MAX(execution_time_ms), 1) AS max_ms
FROM system.serving.served_model_requests
WHERE DATE(request_time) >= CURRENT_DATE() - INTERVAL 7 DAYS
GROUP BY endpoint_name, DATE(request_time)
ORDER BY day DESC, endpoint_name;
```

### 처리량 (Throughput)

**처리량(Throughput)** 은 단위 시간당 처리된 요청 수를 의미합니다. 엔드포인트가 부하를 감당할 수 있는지 판단하는 핵심 지표입니다.

| 메트릭                           | 단위   | 설명                        |
| ----------------------------- | ---- | ------------------------- |
| **RPS (Requests Per Second)** | 요청/초 | 초당 처리 요청 수, 일반 모델에 사용     |
| **TPS (Tokens Per Second)**   | 토큰/초 | LLM 생성 속도, 스트리밍 경험에 직접 영향 |
| **QPS (Queries Per Second)**  | 쿼리/초 | RPS와 동일 개념으로 혼용           |

```sql theme={null}
-- 시간대별 평균 RPS(Requests Per Second) 계산
SELECT
    endpoint_name,
    DATE_TRUNC('hour', request_time) AS hour_bucket,
    COUNT(*) AS total_requests,
    -- 1시간(3600초) 기준 평균 RPS
    ROUND(COUNT(*) / 3600.0, 2) AS avg_rps
FROM system.serving.served_model_requests
WHERE DATE(request_time) >= CURRENT_DATE() - INTERVAL 1 DAYS
GROUP BY endpoint_name, DATE_TRUNC('hour', request_time)
ORDER BY hour_bucket DESC;
```

### 에러율 분류

에러는 HTTP 상태 코드로 분류하며, 원인에 따라 대응 방법이 다릅니다.

| 상태 코드   | 분류            | 일반적인 원인            | 대응 방법                       |
| ------- | ------------- | ------------------ | --------------------------- |
| **400** | 클라이언트 오류      | 잘못된 요청 형식, 스키마 불일치 | 입력 유효성 검증 강화                |
| **429** | Rate Limiting | 클라이언트 요청 폭주        | Rate Limit 설정, 클라이언트 재시도 로직 |
| **500** | 서버 오류         | 모델 로딩 실패, 메모리 부족   | 리소스 확대, 모델 디버깅              |
| **503** | 서비스 불가        | 콜드 스타트, 과부하        | Provisioned Concurrency 설정  |
| **504** | 타임아웃          | 추론 시간 초과           | 타임아웃 임계값 조정, 모델 최적화         |

***

## Inference Tables (추론 테이블)

> 💡 **Inference Table** 은 Model Serving 엔드포인트의 모든 요청과 응답을 **자동으로 Delta 테이블에 기록** 하는 기능입니다. 모델 성능 모니터링, 디버깅, 규정 준수 감사에 활용됩니다.

### 기록되는 정보

| 항목           | 설명                             |
| ------------ | ------------------------------ |
| **요청 입력**    | 모델에 전달된 입력 데이터 (피처, 프롬프트 등)    |
| **응답 출력**    | 모델의 예측 결과 (점수, 생성 텍스트 등)       |
| **타임스탬프**    | 요청/응답 시간                       |
| **지연 시간**    | 추론에 걸린 시간 (밀리초)                |
| **상태 코드**    | HTTP 상태 (200 성공, 4xx/5xx 오류)   |
| **모델 버전**    | 어떤 모델 버전이 응답했는지 (A/B 테스트 시 유용) |
| **토큰 사용량**   | LLM 엔드포인트의 입력/출력 토큰 수          |
| **요청 메타데이터** | 클라이언트 ID, 요청 ID 등 추적 정보        |

### 자동 캡처 설정

```python theme={null}
# 엔드포인트 생성 시 Inference Table 활성화
from databricks.sdk import WorkspaceClient
from databricks.sdk.service.serving import (
    EndpointCoreConfigInput,
    ServedEntityInput,
    AutoCaptureConfigInput,
)

w = WorkspaceClient()

auto_capture = AutoCaptureConfigInput(
    enabled=True,
    catalog_name="ml_prod",
    schema_name="monitoring",
    table_name_prefix="fraud_model"
)

w.serving_endpoints.create(
    name="fraud-detector",
    config=EndpointCoreConfigInput(
        served_entities=[
            ServedEntityInput(
                entity_name="ml_prod.models.fraud_detector",
                entity_version="3",
                workload_size="Small",
                scale_to_zero_enabled=True,
            )
        ],
        auto_capture_config=auto_capture,
    ),
)
# → ml_prod.monitoring.fraud_model_payload 테이블이 자동 생성됩니다
```

> 💡 **Inference Table 이름 규칙**: `{catalog}.{schema}.{prefix}_payload` 형태로 자동 생성됩니다. 기존 엔드포인트에도 `PUT /api/2.0/serving-endpoints/{name}/config`로 활성화할 수 있습니다.

### 페이로드 구조

Inference Table에 기록되는 데이터의 스키마는 다음과 같습니다.

```sql theme={null}
-- Inference Table 스키마 확인
DESCRIBE TABLE ml_prod.monitoring.fraud_model_payload;

-- 주요 컬럼:
-- date              : DATE        (파티션 키)
-- timestamp_ms      : BIGINT      (요청 시각, 밀리초)
-- status_code       : INT         (HTTP 상태 코드)
-- execution_time_ms : DOUBLE      (추론 소요 시간)
-- request           : STRING      (요청 JSON)
-- response          : STRING      (응답 JSON)
-- request_metadata  : MAP<STRING,STRING> (추적 메타데이터)
-- sampling_fraction : DOUBLE      (샘플링 비율)
```

> ⚠️ **주의**: Inference Table은 파티션 기반으로 데이터를 저장하므로, 쿼리 시 반드시 `date` 컬럼으로 필터링하여 성능을 확보하시기 바랍니다.

### 샘플링 전략과 데이터 보존 정책

트래픽이 많은 엔드포인트에서 **모든 요청을 기록하면 스토리지 비용이 빠르게 증가** 합니다. 샘플링 전략과 보존 정책을 적절히 설정해야 합니다.

**샘플링 전략 비교:**

| 전략               | 방법                      | 장점               | 단점           |
| ---------------- | ----------------------- | ---------------- | ------------ |
| **전수 기록 (100%)** | `sampling_fraction=1.0` | 완전한 감사 추적        | 스토리지 비용 높음   |
| **랜덤 샘플링**       | `sampling_fraction=0.1` | 비용 절감, 통계적 대표성   | 희귀 이벤트 누락 가능 |
| **계층적 샘플링**      | 에러는 100%, 정상은 10%       | 오류 완전 캡처 + 비용 절감 | 구현 복잡성       |
| **시간 기반 샘플링**    | 피크 시간대만 100%            | 중요 시간대 완전 캡처     | 비피크 시간대 누락   |

```python theme={null}
# 샘플링 비율 설정 예시 (엔드포인트 업데이트 시)
auto_capture = AutoCaptureConfigInput(
    enabled=True,
    catalog_name="ml_prod",
    schema_name="monitoring",
    table_name_prefix="fraud_model",
    # 10% 샘플링: 고트래픽 환경에서 비용 절감
    # 기본값은 100% (sampling_fraction 미설정 시)
)
```

**데이터 보존 정책 (Delta Table TTL):**

```sql theme={null}
-- Inference Table에 데이터 보존 정책 설정 (90일)
ALTER TABLE ml_prod.monitoring.fraud_model_payload
SET TBLPROPERTIES (
  'delta.deletedFileRetentionDuration' = 'interval 7 days',
  'delta.logRetentionDuration' = 'interval 90 days'
);

-- 90일 이전 데이터 정기 삭제 (Lakeflow Jobs으로 예약)
DELETE FROM ml_prod.monitoring.fraud_model_payload
WHERE date < CURRENT_DATE() - INTERVAL 90 DAYS;

-- VACUUM으로 물리적 파일 정리
VACUUM ml_prod.monitoring.fraud_model_payload RETAIN 168 HOURS;
```

> 💡 **권장 보존 기간**: 규정 준수 요구사항이 없는 경우 30\~90일을 권장합니다. GDPR/개인정보보호법 적용 환경에서는 법적 의무 보존 기간을 반드시 확인하십시오.
