
1. MLOps 관측성(Observability)의 중요성과 기술 스택
머신러닝 모델을 프로덕션 환경에 배포한 후, 모델이 정상적으로 동작하는지 확인하는 것은 단순히 에러 로그를 확인하는 것 이상의 의미를 갖습니다. 고가의 GPU 자원을 얼마나 효율적으로 사용하는지(하드웨어 점유율), 그리고 실제 비즈니스 요청에 대해 얼마나 정확하고 빠르게 응답하는지(추론 성공률 및 지연 시간)를 실시간으로 모니터링해야 합니다. 본 가이드에서는 파이썬(Python) 기반의 애플리케이션에서 Prometheus 포맷으로 메트릭을 노출하고, 이를 Grafana 대시보드로 시각화하여 운영 안정성을 확보하는 구체적인 방법을 다룹니다.
2. Prometheus와 Grafana 연동 구조 및 주요 지표 차이
모니터링 시스템을 구축하기 전, 하드웨어 자원 지표와 애플리케이션 수준의 지표가 어떻게 수집되는지 그 차이를 이해해야 합니다.
| 비교 항목 | 하드웨어 점유율 (Infrastructure Metrics) | 추론 성공률 (Application Metrics) |
|---|---|---|
| 수집 대상 | CPU 사용량, GPU 메모리, 시스템 RAM | HTTP 200 OK 여부, 예측 성공/실패 횟수 |
| 수집 도구 | Node Exporter, NVIDIA DCGM Exporter | prometheus-client (Python SDK) |
| 시각화 초점 | 자원 부족(OOM) 및 병목 현상 감지 | 모델 서비스 가용성 및 품질(SLA) 관리 |
| 데이터 유형 | Gauge (현재 상태 수치) | Counter (누적 횟수) |
| 해결 과제 | 적절한 오토스케일링 시점 파악 | 코드 버그 또는 데이터 드리프트 감지 |
3. 실무 적용을 위한 7가지 Python 기반 모니터링 구현 예제
개발자가 FastAPI나 Flask 환경에서 즉시 모델 메트릭을 노출할 수 있도록 실무형 코드를 제공합니다.
예제 1: prometheus-client를 활용한 추론 성공률 카운터 설정
모델 추론의 성공과 실패 횟수를 기록하여 성공률을 계산하는 기본 구조입니다.
from prometheus_client import Counter, start_http_server
import time
# 메트릭 정의
INFERENCE_REQUESTS = Counter(
'model_inference_total',
'Total number of model inferences',
['model_name', 'status']
)
def predict(data):
try:
# 모델 추론 로직 수행
# result = model.predict(data)
INFERENCE_REQUESTS.labels(model_name='resnet50', status='success').inc()
return {"status": "ok"}
except Exception:
INFERENCE_REQUESTS.labels(model_name='resnet50', status='fail').inc()
return {"status": "error"}
if __name__ == '__main__':
# 8000번 포트로 메트릭 서버 시작
start_http_server(8000)
while True:
time.sleep(1)
예제 2: Gauge를 이용한 실시간 GPU 메모리 점유율 모니터링 커스텀 수집기
NVIDIA 관리 라이브러리를 통해 파이썬 내부에서 직접 GPU 상태를 Prometheus로 전달합니다.
from prometheus_client import Gauge
import pynvml # pip install nvidia-ml-py
GPU_MEM_USAGE = Gauge('gpu_memory_usage_bytes', 'Current GPU memory usage in bytes', ['gpu_id'])
def track_gpu_metrics():
pynvml.nvmlInit()
handle = pynvml.nvmlDeviceGetHandleByIndex(0)
info = pynvml.nvmlDeviceGetMemoryInfo(handle)
GPU_MEM_USAGE.labels(gpu_id='0').set(info.used)
# 주기적으로 실행하여 상태 업데이트
예제 3: FastAPI 미들웨어를 활용한 모든 요청 지연 시간(Latency) 기록
모든 추론 요청의 처리 시간을 히스토그램으로 기록하여 Grafana에서 백분위수(P99)를 시각화합니다.
from prometheus_client import Histogram
from fastapi import FastAPI, Request
import time
app = FastAPI()
LATENCY = Histogram('inference_latency_seconds', 'Inference latency in seconds')
@app.middleware("http")
async def add_prometheus_metrics(request: Request, call_next):
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
LATENCY.observe(process_time)
return response
예제 4: 다중 모델 환경에서의 라벨링(Labeling) 전략
여러 모델을 하나의 서버에서 서빙할 때 모델별로 지표를 구분하는 방법입니다.
# 모델별 성공률 구분을 위한 라벨 활용
def record_inference(model_id, is_success):
status_label = 'success' if is_success else 'error'
INFERENCE_REQUESTS.labels(model_name=model_id, status=status_label).inc()
예제 5: Prometheus 설정 파일(prometheus.yml) 구성
파이썬 애플리케이션에서 노출한 메트릭을 Prometheus가 긁어갈(Scrape) 수 있도록 설정합니다.
scrape_configs:
- job_name: 'python-model-server'
static_configs:
- targets: ['localhost:8000']
scrape_interval: 5s
예제 6: Grafana 추론 성공률 계산을 위한 PromQL 쿼리
성공률을 퍼센트(%)로 대시보드에 표시하기 위한 핵심 쿼리 해결 방법입니다.
# PromQL 예시
sum(rate(model_inference_total{status="success"}[5m]))
/
sum(rate(model_inference_total[5m])) * 100
예제 7: 추론 결과 클래스별 분포(Distribution) 시각화
모델이 특정 클래스로만 편향되게 예측하는지 모니터링하기 위한 Counter 설정입니다.
PREDICTION_CLASSES = Counter('model_prediction_class_total', 'Number of predictions per class', ['class_name'])
def on_prediction(label):
PREDICTION_CLASSES.labels(class_name=label).inc()
4. 시각화 지표 최적화 및 문제 해결 전략
대시보드를 구축할 때 주의해야 할 세 가지 핵심 전략을 제시합니다.
- Cardinality 관리: 너무 많은 라벨(예: 모든 유저 ID를 라벨로 사용)을 사용하면 Prometheus 메모리가 폭발할 수 있습니다. 모델 이름, 상태 코드 등 핵심 범주만 사용하십시오.
- Alerting 연동: Grafana에서 시각화만 하는 것이 아니라, 추론 성공률이 95% 이하로 떨어지면 Slack이나 이메일로 알림이 가도록 설정하십시오.
- 하드웨어와 소프트웨어의 상관관계 분석: GPU 온도가 높아질 때 추론 지연 시간이 늘어나는지 등을 하나의 차트에서 비교 분석하여 인프라 병목을 진단하십시오.