Saltar al contenido principal

Prometheus

Definición

Prometheus es un toolkit de monitoreo y alertas de código abierto originalmente construido en SoundCloud y ahora un proyecto graduado de CNCF. Almacena todos los datos como series temporales: flujos de valores de punto flotante con marca de tiempo identificados por un nombre de métrica y un conjunto de etiquetas clave-valor. Este modelo es una buena opción para datos operativos — uso de CPU, recuentos de solicitudes, tasas de error — y para señales específicas de ML como la latencia de predicción, el rendimiento y las distribuciones de valores de características a lo largo del tiempo.

La elección arquitectónica definitoria en Prometheus es su modelo de scraping basado en pull. En lugar de requerir que las aplicaciones instrumentadas envíen métricas a un recopilador central, Prometheus raspa periódicamente endpoints HTTP (por defecto /metrics) expuestos por los objetivos. Esta inversión del control hace que el descubrimiento de servicios, el control de acceso y la depuración sean significativamente más simples: se puede usar curl en el endpoint de métricas de cualquier objetivo directamente para ver lo que Prometheus recopilará. Los objetivos se descubren mediante configuración estática o descubrimiento de servicios dinámico (Kubernetes, Consul, EC2, etc.).

Prometheus no es una solución de almacenamiento a largo plazo por diseño. Su base de datos de series temporales local (TSDB) está optimizada para la ingesta rápida y la consulta de datos recientes, reteniendo típicamente 15 días. Para el almacenamiento a largo plazo, Prometheus puede escribir de forma remota en sistemas como Thanos, Cortex o VictoriaMetrics. En contextos de ML, Prometheus es la capa de recopilación y alertas; Grafana proporciona la capa de visualización y dashboards encima.

Cómo funciona

Instrumentación de objetivos

Las aplicaciones exponen métricas a través de un endpoint HTTP /metrics en el formato de exposición de Prometheus — un formato de texto plano de líneas nombre_métrica{etiqueta="valor"} valor_numérico marca_de_tiempo. En Python, la biblioteca prometheus_client proporciona tipos Counter, Gauge, Histogram y Summary que manejan el formato de exposición automáticamente. Un proceso de servicio de ML típicamente expone contadores para el total de solicitudes de predicción, histogramas para la latencia de solicitudes y gauges para las versiones del modelo actualmente cargadas y la utilización de recursos.

Scraping y almacenamiento

Prometheus evalúa su archivo de configuración para determinar qué objetivos raspar y a qué intervalo (por defecto: 15 segundos). En cada raspado obtiene el endpoint /metrics, analiza el formato de exposición y escribe las muestras en su TSDB local en fragmentos comprimidos. La TSDB usa un registro de escritura anticipada (WAL) para la durabilidad y compacta los datos en bloques a lo largo del tiempo. La cardinalidad de etiquetas es el principal mecanismo de rendimiento: cada combinación única de valores de etiqueta crea una serie temporal separada, por lo que se deben evitar las etiquetas no acotadas (p. ej., los IDs de usuario).

Consultas PromQL y alertas

PromQL (Lenguaje de Consulta de Prometheus) es un lenguaje de consulta funcional para seleccionar y agregar datos de series temporales. Los vectores instantáneos seleccionan el valor actual de un conjunto de series; los vectores de rango seleccionan una ventana de muestras; las funciones calculan tasas, promedios, cuantiles y predicciones sobre esos vectores. Las reglas de alerta son expresiones PromQL evaluadas a un intervalo configurable; cuando una expresión devuelve un resultado no vacío, la alerta se dispara y se envía al Alertmanager.

Alertmanager

Alertmanager recibe alertas de Prometheus (y otras fuentes), las deduplica, aplica reglas de agrupamiento y enrutamiento, y envía notificaciones a los receptores (PagerDuty, Slack, correo electrónico, webhooks). Los silencios y las reglas de inhibición evitan las tormentas de alertas durante las ventanas de mantenimiento conocidas o los fallos en cascada. En los sistemas de ML, Alertmanager enruta las alertas de degradación del modelo al canal de Slack del equipo de ML mientras las alertas de infraestructura (alta CPU, muertes por OOM) van al equipo de plataforma.

Almacenamiento remoto y federación

Para escenarios multi-clúster o de retención prolongada, Prometheus escribe de forma remota muestras en un backend duradero. La federación permite que un Prometheus global raspe métricas agregadas de instancias de Prometheus regionales. Ambos patrones son comunes en grandes plataformas de ML donde los clústeres de entrenamiento y servicio ejecutan cada uno su propio Prometheus, y una instancia central agrega métricas a nivel de servicio.

Cuándo usar / Cuándo NO usar

Usar cuandoEvitar cuando
Se necesitan métricas operativas para la infraestructura de servicio de ML (latencia, rendimiento, tasa de error)Se necesita almacenar logs de predicción brutos o datos de eventos de alta cardinalidad
Se quiere un stack de monitoreo basado en pull y auto-hospedado sin dependencia de proveedorEl equipo carece de experiencia en infraestructura para operar y ajustar un stack de Prometheus
Se ejecuta en Kubernetes y se quiere descubrimiento de servicios nativoSe necesita retención a largo plazo (>15 días) sin configuración adicional de almacenamiento remoto
Se necesitan alertas potentes con deduplicación y enrutamiento vía AlertmanagerSe necesitan intervalos de scraping inferiores a un segundo; Prometheus está diseñado para intervalos de 10-60 segundos
Se quiere un backend estándar para los dashboards de GrafanaLa aplicación genera cardinalidad de etiquetas no acotada, lo que degradará el rendimiento de la TSDB

Comparaciones

Prometheus y Grafana son herramientas complementarias, no competidoras. La tabla a continuación describe cuándo usarlas juntas versus alternativas.

CriterioPrometheusGrafana
RolRecopilar, almacenar y alertar sobre métricasVisualizar y explorar métricas desde cualquier fuente de datos
Lenguaje de consultaPromQL (lenguaje funcional optimizado para métricas)Por fuente de datos (PromQL para Prometheus, SQL para otros)
AlertasReglas de alerta integradas + AlertmanagerAlertas de Grafana (unificadas, múltiples fuentes de datos)
Fuentes de datosPropio (TSDB)Prometheus, InfluxDB, Loki, Elasticsearch, bases de datos, etc.
AlmacenamientoTSDB local, escritura remota para retención a largo plazoSin almacenamiento — puramente una capa de consulta y visualización
Cuándo usar juntosSiempre — Prometheus recopila, Grafana muestraSiempre — usar Grafana como interfaz para los datos de Prometheus

Ventajas y desventajas

AspectoVentajasDesventajas
Arquitectura basada en pullDepuración simple, control de acceso a nivel de objetivoRequiere que los objetivos expongan endpoints HTTP
PromQLExpresivo, componible, creado para métricasCurva de aprendizaje pronunciada en comparación con SQL
TSDB localIngesta y consulta rápidas para datos recientesRetención limitada; necesita almacenamiento remoto para largo plazo
Modelo de etiquetasFiltrado y agregación multidimensional flexibleLas etiquetas de alta cardinalidad causan problemas de memoria y rendimiento de consultas
AlertmanagerEnrutamiento, agrupamiento y silenciamiento enriquecidosComponente separado a operar; la configuración puede volverse compleja
EcosistemaGran biblioteca de exportadores y bibliotecas clienteSobrecarga operativa para despliegues auto-hospedados

Ejemplos de código

# ml_metrics_server.py
# Exposes ML model metrics via prometheus_client for Prometheus scraping.
# Run: pip install prometheus_client flask scikit-learn numpy
# Then configure Prometheus to scrape localhost:8000

import time
import threading
import random
import numpy as np
from prometheus_client import (
Counter,
Histogram,
Gauge,
start_http_server,
REGISTRY,
)
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier

# --- Define metrics ---

PREDICTION_COUNTER = Counter(
"ml_predictions_total",
"Total number of prediction requests",
["model_name", "model_version", "status"], # labels
)

PREDICTION_LATENCY = Histogram(
"ml_prediction_latency_seconds",
"Prediction request latency in seconds",
["model_name", "model_version"],
buckets=[0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5],
)

MODEL_CONFIDENCE = Histogram(
"ml_prediction_confidence",
"Distribution of model prediction confidence scores",
["model_name", "model_version"],
buckets=[0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0],
)

ACTIVE_MODEL_VERSION = Gauge(
"ml_active_model_version",
"Currently active model version (encoded as numeric)",
["model_name"],
)

DATA_DRIFT_SCORE = Gauge(
"ml_data_drift_score",
"Current data drift score (PSI) for the primary feature set",
["model_name", "feature_set"],
)

# --- Load and train a simple model ---
X, y = load_iris(return_X_y=True)
clf = RandomForestClassifier(n_estimators=50, random_state=42)
clf.fit(X, y)

MODEL_NAME = "iris-classifier"
MODEL_VERSION = "1.0.0"
ACTIVE_MODEL_VERSION.labels(model_name=MODEL_NAME).set(1)


def simulate_prediction(features: np.ndarray) -> dict:
"""Run a prediction and record Prometheus metrics."""
start = time.time()
try:
proba = clf.predict_proba(features.reshape(1, -1))[0]
predicted_class = int(np.argmax(proba))
confidence = float(np.max(proba))

# Record latency and confidence
duration = time.time() - start
PREDICTION_LATENCY.labels(
model_name=MODEL_NAME, model_version=MODEL_VERSION
).observe(duration)
MODEL_CONFIDENCE.labels(
model_name=MODEL_NAME, model_version=MODEL_VERSION
).observe(confidence)
PREDICTION_COUNTER.labels(
model_name=MODEL_NAME,
model_version=MODEL_VERSION,
status="success",
).inc()

return {"class": predicted_class, "confidence": confidence}
except Exception as exc:
PREDICTION_COUNTER.labels(
model_name=MODEL_NAME,
model_version=MODEL_VERSION,
status="error",
).inc()
raise exc


def simulate_drift_monitoring():
"""Periodically update a synthetic drift score gauge."""
while True:
# In production this would run a real PSI/KS test
drift_score = random.uniform(0.01, 0.35)
DATA_DRIFT_SCORE.labels(
model_name=MODEL_NAME, feature_set="sepal"
).set(drift_score)
time.sleep(30)


def simulate_traffic():
"""Generate synthetic prediction traffic for demonstration."""
samples = X[np.random.choice(len(X), size=10)]
for sample in samples:
simulate_prediction(sample)
time.sleep(random.uniform(0.05, 0.3))


if __name__ == "__main__":
# Start Prometheus metrics HTTP server on port 8000
start_http_server(8000)
print("Prometheus metrics server running on http://localhost:8000/metrics")
print("Configure Prometheus to scrape this endpoint.")

# Start background drift monitor
drift_thread = threading.Thread(target=simulate_drift_monitoring, daemon=True)
drift_thread.start()

# Simulate continuous prediction traffic
print("Simulating prediction traffic...")
while True:
simulate_traffic()
time.sleep(1)

Recursos prácticos

Ver también