Integración de Métricas con Prometheus y Grafana

Lectura
25 min~4 min lectura

Concepto clave

En el despliegue de APIs de Machine Learning, el monitoreo es como tener un tablero de control en un coche de carreras. No solo necesitas saber si el motor funciona, sino también su temperatura, presión de aceite y consumo de combustible en tiempo real. Prometheus es el sistema que recoge estas métricas (como un registrador de datos), mientras que Grafana es el panel de instrumentos que las visualiza de forma comprensible.

En el contexto de FastAPI, integrar estas herramientas te permite responder preguntas críticas: ¿Cuántas predicciones por segundo está procesando tu modelo? ¿Cuál es el tiempo de respuesta p95? ¿Hay errores en las validaciones de entrada? Sin esto, operas a ciegas, arriesgando caídas del servicio o degradación silenciosa del rendimiento.

Cómo funciona en la práctica

El flujo típico sigue estos pasos:

  1. Instrumentas tu aplicación FastAPI con un cliente de Prometheus (como prometheus-fastapi-instrumentator) que expone métricas en un endpoint /metrics.
  2. Prometheus "raspa" periódicamente ese endpoint (cada 15-30 segundos) y almacena las métricas en su base de datos de series temporales.
  3. Grafana se conecta a Prometheus como fuente de datos, permitiéndote crear dashboards con gráficos, alertas y paneles personalizados.
  4. Para APIs de ML, añades métricas específicas como latencia de inferencia, distribución de scores del modelo, o conteo de predicciones por clase.

Codigo en accion

Primero, instala las dependencias necesarias:

pip install prometheus-fastapi-instrumentator

Luego, integra el instrumentador en tu aplicación FastAPI. Aquí el "antes" (sin monitoreo) y "después" (con monitoreo):

Antes: API básica sin métricas.

from fastapi import FastAPI
import numpy as np

app = FastAPI()

@app.post("/predict")
async def predict(data: dict):
    # Simulación de inferencia de ML
    prediction = np.random.rand()
    return {"prediction": float(prediction)}

Después: API instrumentada con métricas estándar y personalizadas.

from fastapi import FastAPI, Request
from prometheus_fastapi_instrumentator import Instrumentator
import numpy as np
import time
from prometheus_client import Counter, Histogram

app = FastAPI()

# Métricas personalizadas para ML
PREDICTION_COUNTER = Counter('ml_predictions_total', 'Total de predicciones realizadas')
PREDICTION_LATENCY = Histogram('ml_prediction_latency_seconds', 'Latencia de predicción')

Instrumentator().instrument(app).expose(app)

@app.post("/predict")
async def predict(request: Request, data: dict):
    start_time = time.time()
    
    # Simulación de inferencia de ML
    prediction = np.random.rand()
    
    # Registrar métricas
    PREDICTION_COUNTER.inc()
    PREDICTION_LATENCY.observe(time.time() - start_time)
    
    return {"prediction": float(prediction)}

Errores comunes

  • Exponer el endpoint /metrics sin autenticación en producción: Cualquiera podría acceder a métricas sensibles. Solución: Usa middleware de autenticación o despliega Prometheus en la misma red privada.
  • No etiquetar métricas adecuadamente: Por ejemplo, tener solo ml_predictions_total sin etiquetas como model_version o endpoint. Esto dificulta el análisis cuando tienes múltiples modelos. Agrega etiquetas con .labels() en Prometheus Client.
  • Configurar intervalos de scrape demasiado cortos: Si Prometheus consulta cada segundo, puede saturar tu API. En producción, 15-30 segundos es un buen balance entre granularidad y carga.
  • Olvidar métricas de negocio para ML: Además de latencia y errores, monitorea la distribución de scores, drift de datos, o precisión en tiempo real si tienes ground truth.

Checklist de dominio

  1. El endpoint /metrics responde con datos en formato Prometheus.
  2. Prometheus está configurado para scrapear tu API y almacena las métricas.
  3. Grafana muestra un dashboard con al menos: requests por segundo, latencia por percentil, y tasa de errores.
  4. Tienes métricas personalizadas para tu modelo ML (ej. predicciones por clase, confianza media).
  5. Las alertas en Grafana notifican cuando la latencia p95 supera un umbral (ej. 500ms).
  6. Probaste el flujo completo localmente antes de desplegar a producción.
  7. Documentaste cómo añadir nuevas métricas y dashboards al equipo.

Implementa un sistema de monitoreo para un API de clasificación de imágenes

En este ejercicio, extenderás una API FastAPI existente para monitorear el rendimiento de un modelo de clasificación de imágenes (simulado). Sigue estos pasos:

  1. Clona el repositorio base desde https://github.com/ejemplo/ml-monitoring-base (simulado) o crea un archivo main.py con una API FastAPI que tenga un endpoint /classify que reciba una imagen (como bytes) y devuelva una clase predicha (ej. "perro", "gato"). Simula la inferencia con time.sleep(0.1) y una clase aleatoria.
  2. Instala prometheus-fastapi-instrumentator y prometheus-client.
  3. Instrumenta la aplicación para exponer métricas estándar en /metrics.
  4. Añade dos métricas personalizadas usando prometheus_client:
    • Un contador images_classified_total con etiquetas para la clase predicha (ej. label="perro").
    • Un histograma classification_latency_seconds para medir el tiempo de inferencia.
  5. Ejecuta la API y verifica que curl localhost:8000/metrics muestre tus métricas.
  6. Configura Prometheus local (usa Docker con docker run -p 9090:9090 prom/prometheus) para scrapear tu API cada 15 segundos. Crea un archivo prometheus.yml con el job adecuado.
  7. En Grafana (usa docker run -p 3000:3000 grafana/grafana), conecta Prometheus como fuente de datos y crea un dashboard con:
    • Un gráfico de líneas para rate(images_classified_total[5m]) por clase.
    • Un panel para la latencia p95: histogram_quantile(0.95, rate(classification_latency_seconds_bucket[5m])).
  8. Genera tráfico de prueba con una herramienta como locust o scripts simples, y observa cómo se actualizan los dashboards.
Pistas
  • Usa PREDICTION_COUNTER.labels(class="perro").inc() para incrementar el contador con etiquetas.
  • En Prometheus, el job en prometheus.yml debe apuntar a localhost:8000 bajo static_configs.
  • Para Grafana, la URL de Prometheus es http://host.docker.internal:9090 si usas Docker en macOS/Windows, o http://localhost:9090 en Linux.

Evalua tu comprension

Completa el quiz interactivo de arriba para ganar XP.