Prometheus
Definição
Prometheus é um toolkit open source de monitoramento e alertas de sistemas originalmente construído no SoundCloud e agora um projeto graduado da CNCF. Ele armazena todos os dados como séries temporais: fluxos de valores de ponto flutuante com timestamp identificados por um nome de métrica e um conjunto de labels de chave-valor. Esse modelo é perfeitamente adequado para dados operacionais — uso de CPU, contagens de requisições, taxas de erro — e para sinais específicos de ML, como latência de previsão, throughput e distribuições de valores de features ao longo do tempo.
A escolha arquitetural definidora do Prometheus é seu modelo de scraping pull-based. Em vez de exigir que aplicações instrumentadas enviem métricas para um coletor central, o Prometheus periodicamente faz scraping de endpoints HTTP (por padrão /metrics) expostos pelos alvos. Essa inversão de controle torna a descoberta de serviços, o controle de acesso e a depuração significativamente mais simples: você pode fazer curl no endpoint de métricas de qualquer alvo diretamente para ver o que o Prometheus coletará. Os alvos são descobertos via configuração estática ou descoberta dinâmica de serviços (Kubernetes, Consul, EC2, etc.).
O Prometheus não é uma solução de armazenamento de longo prazo por design. Seu banco de dados de séries temporais local (TSDB) é otimizado para ingestão rápida e consulta de dados recentes, tipicamente retendo 15 dias. Para armazenamento de longo prazo, o Prometheus pode fazer remote-write para sistemas como Thanos, Cortex ou VictoriaMetrics. Em contextos de ML, o Prometheus é a camada de coleta e alertas; o Grafana fornece a camada de visualização e dashboards por cima.
Como funciona
Instrumentação de alvos
As aplicações expõem métricas via um endpoint HTTP /metrics no formato de exposição do Prometheus — um formato de texto simples de linhas nome_metrica{label="valor"} valor_numerico timestamp. Em Python, a biblioteca prometheus_client fornece os tipos Counter, Gauge, Histogram e Summary que lidam com o formato de exposição automaticamente. Um processo de serviço de ML tipicamente expõe contadores para o total de requisições de previsão, histogramas para latência de requisições e gauges para versões de modelos atualmente carregadas e utilização de recursos.
Scraping e armazenamento
O Prometheus avalia seu arquivo de configuração para determinar quais alvos fazer scraping e em qual intervalo (padrão: 15 segundos). Em cada scraping, ele busca o endpoint /metrics, analisa o formato de exposição e grava as amostras em seu TSDB local em blocos comprimidos. O TSDB usa um write-ahead log (WAL) para durabilidade e compacta dados em blocos ao longo do tempo. A cardinalidade de labels é a principal alavanca de desempenho: cada combinação única de valores de label cria uma série temporal separada, então labels ilimitadas (por exemplo, IDs de usuários) devem ser evitadas.
Consultas PromQL e alertas
PromQL (Prometheus Query Language) é uma linguagem de consulta funcional para selecionar e agregar dados de séries temporais. Vetores instantâneos selecionam o valor atual de um conjunto de séries; vetores de intervalo selecionam uma janela de amostras; funções calculam taxas, médias, quantis e previsões sobre esses vetores. As regras de alerta são expressões PromQL avaliadas em um intervalo configurável; quando uma expressão retorna um resultado não vazio, o alerta dispara e é enviado ao Alertmanager.
Alertmanager
O Alertmanager recebe alertas do Prometheus (e outras fontes), os deduplica, aplica regras de agrupamento e roteamento e despacha notificações para receptores (PagerDuty, Slack, email, webhooks). Silêncios e regras de inibição previnem tempestades de alertas durante janelas de manutenção conhecidas ou falhas em cascata. Em sistemas de ML, o Alertmanager roteia alertas de degradação de modelos para o canal Slack da equipe de ML enquanto alertas de infraestrutura (CPU alta, OOM kills) vão para a equipe de plataforma.
Armazenamento remoto e federação
Para cenários multi-cluster ou de longa retenção, o Prometheus faz remote-write de amostras para um backend durável. A federação permite que um Prometheus global faça scraping de métricas agregadas de instâncias regionais do Prometheus. Ambos os padrões são comuns em grandes plataformas de ML onde clusters de treinamento e clusters de serviço cada um executa seu próprio Prometheus, e uma instância central agrega métricas de nível de serviço.
Quando usar / Quando NÃO usar
| Usar quando | Evitar quando |
|---|---|
| Você precisa de métricas operacionais para infraestrutura de serviço de ML (latência, throughput, taxa de erro) | Você precisa armazenar logs de previsões brutos ou dados de eventos de alta cardinalidade |
| Você quer uma stack de monitoramento pull-based e auto-hospedada sem lock-in de fornecedor | Sua equipe não tem experiência de infraestrutura para operar e ajustar uma stack do Prometheus |
| Você está rodando no Kubernetes e quer descoberta de serviços nativa | Você precisa de retenção de longo prazo (>15 dias) sem configuração adicional de armazenamento remoto |
| Você precisa de alertas poderosos com deduplicação e roteamento via Alertmanager | Você precisa de intervalos de scraping abaixo de um segundo; o Prometheus é projetado para intervalos de 10 a 60 segundos |
| Você quer um backend padrão para dashboards do Grafana | Sua aplicação gera cardinalidade de label ilimitada, o que degradará o desempenho do TSDB |
Comparações
O Prometheus e o Grafana são complementares, não ferramentas concorrentes. A tabela abaixo descreve quando usá-los juntos versus alternativas.
| Critério | Prometheus | Grafana |
|---|---|---|
| Papel | Coletar, armazenar e alertar sobre métricas | Visualizar e explorar métricas de qualquer fonte de dados |
| Linguagem de consulta | PromQL (linguagem funcional otimizada para métricas) | Por fonte de dados (PromQL para Prometheus, SQL para outros) |
| Alertas | Regras de alerta integradas + Alertmanager | Grafana Alerting (unificado, multi-fontes de dados) |
| Fontes de dados | Apenas si mesmo (TSDB) | Prometheus, InfluxDB, Loki, Elasticsearch, bancos de dados, etc. |
| Armazenamento | TSDB local, remote-write para longo prazo | Sem armazenamento — puramente uma camada de consulta e visualização |
| Quando usar juntos | Sempre — o Prometheus coleta, o Grafana exibe | Sempre — use o Grafana como interface para os dados do Prometheus |
Vantagens e desvantagens
| Aspecto | Vantagens | Desvantagens |
|---|---|---|
| Arquitetura pull-based | Depuração simples, controle de acesso no nível do alvo | Requer que os alvos exponham endpoints HTTP |
| PromQL | Expressivo, composável, projetado especificamente para métricas | Curva de aprendizado íngreme em comparação com SQL |
| TSDB local | Ingestão rápida e consulta para dados recentes | Retenção limitada; precisa de armazenamento remoto para longo prazo |
| Modelo de labels | Filtragem e agregação multidimensional flexíveis | Labels de alta cardinalidade causam problemas de memória e desempenho de consulta |
| Alertmanager | Roteamento, agrupamento e silenciamento avançados | Componente separado para operar; a configuração pode se tornar complexa |
| Ecossistema | Enorme biblioteca de exporters e bibliotecas cliente | Sobrecarga operacional para implantações auto-hospedadas |
Exemplos 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áticos
- Documentação do Prometheus — Documentação oficial cobrindo arquitetura, configuração, PromQL, alertas e melhores práticas.
- Biblioteca Python prometheus_client — Cliente Python oficial para instrumentar aplicações; cobre todos os tipos de métricas e o formato de exposição.
- Cheat sheet de PromQL — Referência concisa para operadores PromQL, funções e padrões comuns.
- Robust Perception — Monitoramento com Prometheus — Blog aprofundado de Brian Brazil cobrindo internos do Prometheus, padrões PromQL e conselhos operacionais.
- Awesome Prometheus — Lista curada de exporters do Prometheus, dashboards e recursos da comunidade.