Zum Hauptinhalt springen

Prometheus

Definition

Prometheus ist ein Open-Source-Monitoring- und Alerting-Toolkit, das ursprünglich bei SoundCloud entwickelt wurde und jetzt ein graduiertes CNCF-Projekt ist. Es speichert alle Daten als Zeitreihen: Ströme von mit Zeitstempeln versehenen Gleitkomma-Werten, identifiziert durch einen Metriknamen und eine Menge von Key-Value-Labels. Dieses Modell eignet sich hervorragend für Betriebsdaten — CPU-Auslastung, Anfragezählungen, Fehlerquoten — und für ML-spezifische Signale wie Vorhersagelatenz, Durchsatz und Feature-Wertverteilungen über die Zeit.

Die definierende architektonische Entscheidung in Prometheus ist sein pull-basiertes Scraping-Modell. Anstatt instrumentierte Anwendungen dazu zu zwingen, Metriken an einen zentralen Collector zu pushen, scrapt Prometheus periodisch HTTP-Endpunkte (standardmäßig /metrics), die von Zielen bereitgestellt werden. Diese Inversion of Control macht Service-Discovery, Zugangskontrolle und Debugging erheblich einfacher: Man kann den Metrik-Endpunkt jedes Ziels direkt per curl abfragen, um zu sehen, was Prometheus sammeln wird. Ziele werden über statische Konfiguration oder dynamische Service-Discovery (Kubernetes, Consul, EC2 usw.) entdeckt.

Prometheus ist von Natur aus keine Langzeitspeicherlösung. Seine lokale Zeitreihendatenbank (TSDB) ist für schnelle Aufnahme und Abfrage aktueller Daten optimiert und behält typischerweise 15 Tage bei. Für Langzeitspeicherung kann Prometheus Remote-Write an Systeme wie Thanos, Cortex oder VictoriaMetrics verwenden. In ML-Kontexten ist Prometheus die Sammel- und Alerting-Schicht; Grafana bietet die Visualisierungs- und Dashboarding-Schicht darüber.

Funktionsweise

Ziel-Instrumentierung

Anwendungen stellen Metriken über einen HTTP-/metrics-Endpunkt im Prometheus-Exposition-Format bereit — ein Klartextformat aus Metrikname{Label="Wert"} numerischer_Wert Zeitstempel-Zeilen. In Python bietet die prometheus_client-Bibliothek Counter-, Gauge-, Histogram- und Summary-Typen, die das Exposition-Format automatisch verarbeiten. Ein ML-Serving-Prozess stellt typischerweise Counter für die Gesamtzahl der Vorhersageanfragen, Histogramme für die Anfrage-Latenz und Gauges für aktuell geladene Modellversionen und Ressourcenauslastung bereit.

Scraping und Speicherung

Prometheus wertet seine Konfigurationsdatei aus, um zu bestimmen, welche Ziele wie oft gescrapt werden sollen (Standard: 15 Sekunden). Bei jedem Scrape holt er den /metrics-Endpunkt ab, parst das Exposition-Format und schreibt die Samples in seine lokale TSDB in komprimierten Chunks. Die TSDB verwendet ein Write-Ahead-Log (WAL) für Dauerhaftigkeit und verdichtet Daten über die Zeit in Blöcke. Label-Kardinalität ist der wichtigste Leistungshebel: Jede einzigartige Kombination von Label-Werten erstellt eine separate Zeitreihe, daher müssen ungebundene Labels (z. B. Benutzer-IDs) vermieden werden.

PromQL-Abfragen und Alerting

PromQL (Prometheus Query Language) ist eine funktionale Abfragesprache zum Auswählen und Aggregieren von Zeitreihendaten. Instant-Vektoren wählen den aktuellen Wert einer Menge von Serien aus; Range-Vektoren wählen ein Fenster von Samples aus; Funktionen berechnen Raten, Durchschnitte, Quantile und Vorhersagen über diese Vektoren. Alerting-Regeln sind PromQL-Ausdrücke, die in einem konfigurierbaren Intervall ausgewertet werden; wenn ein Ausdruck ein nicht-leeres Ergebnis zurückgibt, wird der Alert ausgelöst und an den Alertmanager gesendet.

Alertmanager

Der Alertmanager empfängt Alerts von Prometheus (und anderen Quellen), dedupliziert sie, wendet Gruppierungs- und Routing-Regeln an und sendet Benachrichtigungen an Empfänger (PagerDuty, Slack, E-Mail, Webhooks). Silences und Inhibition-Regeln verhindern Alert-Stürme während bekannter Wartungsfenster oder kaskadierende Ausfälle. In ML-Systemen leitet der Alertmanager Modell-Degradations-Alerts an den Slack-Kanal des ML-Teams weiter, während Infrastruktur-Alerts (hohe CPU, OOM-Kills) an das Platform-Team gehen.

Remote-Speicherung und Federation

Für Multi-Cluster- oder Langzeitaufbewahrungsszenarien schreibt Prometheus Samples remote in ein dauerhaftes Backend. Federation ermöglicht es einem globalen Prometheus, aggregierte Metriken von regionalen Prometheus-Instanzen zu scrapen. Beide Muster sind in großen ML-Plattformen üblich, wo Trainings-Cluster und Serving-Cluster jeweils ihren eigenen Prometheus betreiben und eine zentrale Instanz Service-Level-Metriken aggregiert.

Wann verwenden / Wann NICHT verwenden

Verwenden wennVermeiden wenn
Betriebsmetriken für ML-Serving-Infrastruktur benötigt werden (Latenz, Durchsatz, Fehlerquote)Rohe Vorhersage-Logs oder hochkardinalitäts-Ereignisdaten gespeichert werden müssen
Ein pull-basierter, selbst gehosteter Monitoring-Stack ohne Vendor-Lock-in gewünscht wirdDas Team keine Infrastrukturerfahrung für den Betrieb und die Abstimmung eines Prometheus-Stacks hat
Kubernetes verwendet wird und native Service-Discovery gewünscht wirdLangzeitaufbewahrung (>15 Tage) ohne zusätzliches Remote-Storage-Setup benötigt wird
Leistungsstarkes Alerting mit Deduplizierung und Routing über Alertmanager benötigt wirdSub-Sekunden-Scrape-Intervalle benötigt werden; Prometheus ist für 10–60 Sekunden ausgelegt
Ein Standard-Backend für Grafana-Dashboards benötigt wirdDie Anwendung unbegrenzte Label-Kardinalität erzeugt, was die TSDB-Leistung beeinträchtigt

Vergleiche

Prometheus und Grafana sind komplementäre, nicht konkurrierende Werkzeuge. Die folgende Tabelle beschreibt, wann sie gemeinsam oder als Alternativen verwendet werden.

KriteriumPrometheusGrafana
RolleMetriken sammeln, speichern und darüber alertierenMetriken aus beliebiger Datenquelle visualisieren und erkunden
AbfragesprachePromQL (metriken-optimierte funktionale Sprache)Pro Datenquelle (PromQL für Prometheus, SQL für andere)
AlertingIntegrierte Alerting-Regeln + AlertmanagerGrafana Alerting (einheitlich, multi-Datenquellen)
DatenquellenSelbst (TSDB)Prometheus, InfluxDB, Loki, Elasticsearch, Datenbanken usw.
SpeicherungLokale TSDB, Remote-Write für LangzeitaufbewahrungKein Speicher — reine Query- und Visualisierungsschicht
Gemeinsamer EinsatzImmer — Prometheus sammelt, Grafana zeigtImmer — Grafana als UI für Prometheus-Daten verwenden

Vor- und Nachteile

AspektVorteileNachteile
Pull-basierte ArchitekturEinfaches Debugging, Zugangskontrolle auf ZielebeneZiele müssen HTTP-Endpunkte bereitstellen
PromQLAusdrucksstark, komponierbar, zweckgebaut für MetrikenSteile Lernkurve im Vergleich zu SQL
Lokale TSDBSchnelle Aufnahme und Abfrage für aktuelle DatenBegrenzte Aufbewahrung; Remote-Speicherung für Langzeitaufbewahrung erforderlich
Label-ModellFlexibles mehrdimensionales Filtern und AggregierenHochkardinalitäts-Labels verursachen Speicher- und Abfrageleistungsprobleme
AlertmanagerUmfangreiches Routing, Gruppierung und StummschaltungSeparate Komponente zu betreiben; Konfiguration kann komplex werden
ÖkosystemGroße Bibliothek von Exportern und Client-BibliothekenOperativer Overhead für selbst gehostete Deployments

Code-Beispiele

# 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)

Praktische Ressourcen

Siehe auch