Ein Histogramm ist ein Metriktyp, der die Verteilung von Messwerten wie Request-Dauern erfasst, indem er Beobachtungen in Buckets zählt und zusätzlich Summe und Anzahl speichert. Anders als ein Mittelwert erlaubt ein Histogramm, Perzentile wie p95 oder p99 zu schätzen und Verteilungen korrekt über viele Instanzen und Zeitfenster zu aggregieren.
Was ist ein Histogramm?
Ein Histogramm ist in der Observability ein Metrik-Typ, der festhält, wie sich Werte verteilen, und nicht nur ihren Durchschnitt. Jedes Mal, wenn ein Request endet, wird seine Dauer „beobachtet“: Das Histogramm erhöht den Zähler des passenden Buckets, addiert den Wert zu einer laufenden Summe und erhöht die Gesamtzahl. Aus diesen Zählern lassen sich später Fragen beantworten wie „Wie viele Requests dauerten länger als 300 ms?“ oder „Wie hoch war die p99-Latenz der letzten fünf Minuten?“.
Histogramme sind der Standard, um Latenzen, Payload-Größen, Wartezeiten in Queues und ähnliche Werte zu messen, bei denen das Tail wichtiger ist als der Mittelwert. Weil Bucket-Zähler einfache Zahlen sind, lassen sich Histogramme von Hunderten Pods addieren und ergeben trotzdem eine gültige Verteilung. Für vorab berechnete Perzentile gilt das nicht.
Klassische Prometheus-Histogramme und le-Buckets
Ein klassisches Prometheus-Histogramm namens http_request_duration_seconds liefert drei Arten von Zeitreihen:
http_request_duration_seconds_bucket{le="0.25"}: kumulative Zähler, einer pro Obergrenze (lesteht für „less than or equal“), immer inklusivele="+Inf".http_request_duration_seconds_sum: die Summe aller beobachteten Werte.http_request_duration_seconds_count: die Anzahl der Beobachtungen, identisch mit dem+Inf-Bucket.
Die Bucket-Grenzen werden bei der Instrumentierung festgelegt. Viele Prometheus-Client-Bibliotheken nutzen standardmäßig 5 ms bis 10 s (.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10). Jeder Bucket ist pro Label-Kombination eine eigene Zeitreihe. Zehn Buckets mal viele Labels treiben die Kardinalität daher schnell nach oben.
Perzentile mit histogram_quantile berechnen
In PromQL schätzen Sie ein Perzentil aus den Bucket-Raten:
histogram_quantile(0.99,
sum by (le, service) (rate(http_request_duration_seconds_bucket[5m])))
Die Funktion sucht den Bucket, der den gesuchten Rang enthält, und interpoliert darin linear. Das Ergebnis ist eine Schätzung, deren Genauigkeit vom Bucket-Layout abhängt: Liegen die Grenzen bei 250 ms und 500 ms, bedeutet ein ausgewiesenes p99 von 400 ms nur „irgendwo zwischen 250 und 500 ms“. Aggregieren Sie immer zuerst mit sum by (le) und behalten Sie das Label le in der Gruppierung.
Exponentielle und native Histogramme
Feste Buckets erzwingen einen Kompromiss zwischen Genauigkeit und Kosten. Zwei neuere Formate lösen das mit exponentiell wachsenden Buckets, die keine manuelle Konfiguration brauchen:
| Format | Buckets | Hinweise |
|---|---|---|
| Klassisches Prometheus-Histogramm | Feste, selbst definierte le-Grenzen | Eine Zeitreihe pro Bucket, breit unterstützt |
| OpenTelemetry Explicit Bucket Histogram | Feste Grenzen pro Instrument oder View | Entspricht dem klassischen Histogramm |
| OpenTelemetry Exponential Histogram | Basis 2^(2^-scale), Scale passt sich automatisch an | Begrenzte Bucket-Anzahl, konstanter relativer Fehler |
| Prometheus Native Histogram | Exponentielles Schema, sparse Buckets | Ganzes Histogramm in einer Zeitreihe; stabil seit Prometheus 3.8, Scraping per Opt-in |
Mit exponentiellen Buckets ist der relative Fehler bei 2 ms genauso groß wie bei 20 s, und das SDK senkt die Scale, wenn die Werte zu weit streuen. Native Histograms und OTel-Exponential-Histogramme sind ineinander überführbar und reduzieren die Zahl der Zeitreihen gegenüber klassischen Buckets erheblich.
Rechenbeispiel: ein Histogramm lesen
Ein illustratives Zeitfenster für einen Service zeigt folgende Bucket-Raten pro Sekunde: le="0.1" 900, le="0.25" 970, le="0.5" 995 und le="+Inf" 1000. Demnach waren 90 Prozent der Requests nach 100 ms fertig, 97 Prozent nach 250 ms und 99,5 Prozent nach 500 ms. Der p99-Rang (990) liegt im Bucket zwischen 250 und 500 ms, der 25 Requests pro Sekunde enthält; die lineare Interpolation landet bei etwa 450 ms. Die 5 Requests pro Sekunde oberhalb von 500 ms werden zwar gezählt, ihre genaue Dauer bleibt aber unbekannt. Deshalb sollte der höchste endliche Bucket oberhalb jedes Werts liegen, der für Sie relevant ist, etwa oberhalb Ihres Timeouts.
Histogramm oder Summary?
Prometheus kennt zusätzlich den Typ Summary, der Quantile direkt im Client berechnet. Für eine einzelne Instanz sind Summaries präzise, ihre Quantile lassen sich aber nicht über Instanzen mitteln oder addieren. Für Services mit mehr als einer Replica ist das Histogramm daher fast immer die bessere Wahl. Histogramme können außerdem Exemplars tragen, also Trace-IDs an einzelnen Buckets, die einen langsamen Bucket direkt mit einem repräsentativen Trace verknüpfen.
Best Practices und typische Fehler
- Bucket-Grenzen auf SLO-Schwellen legen. Lautet das Ziel „99 Prozent unter 300 ms“, liefert ein Bucket
le="0.3"ein exaktes Verhältnis statt einer interpolierten Schätzung. - Exponentielle oder native Histogramme bevorzugen, wo Ihr Stack sie unterstützt, damit Sie kein Bucket-Layout raten müssen.
- Keine Perzentile mitteln. Erst Bucket-Zähler aggregieren, dann das Quantil berechnen.
- Label-Kardinalität im Blick behalten. Ein Histogramm mit User-IDs als Label vervielfacht jeden Bucket.
- Summe und Anzahl mitnutzen:
rate(_sum) / rate(_count)ergibt den Mittelwert, eine sinnvolle Ergänzung zum Tail.
Wie Obseria hilft
Obseria nimmt OpenTelemetry-Histogramme über OTLP entgegen, auch exponentielle, und unterstützt neben OQL und SQL auch PromQL, sodass bestehende histogram_quantile-Abfragen weiter funktionieren. Metrik-Datenpunkte werden 13 Monate aufbewahrt, was langfristige Latenzverteilungen und SLO-Reporting ermöglicht. Über Exemplars gelangen Sie von einem Bucket direkt zum passenden Trace im Distributed Tracing.