Prometheus-Monitoring für Java-Entwickler

Java

Instrumentieren von Java-Anwendungen

Bisher stellte der Artikel Prometheus allgemein vor und beschrieb anhand von Beispielen, wie sich die Software aufsetzen lässt und die ersten Queries durchgeführt werden. Für den effizienten Einsatz von Prometheus für Java-Serveranwendungen reicht es jedoch nicht, mit bestehenden Exportern Betriebssysteme zu überwachen. Ziel ist es daher, dass Java-Anwendungen aktiv Metriken über ihren internen Zustand bereitstellen.

Alle Metriken laufen im Prometheus-Server zusammen und können mithilfe von PromQL ausgewertet und miteinander in Relation gebracht werden. Beispiele für typische Metriken von Java-Applikationen sind Anzahl und Dauer von Aufrufen pro REST-URL oder die Anzahl von Business-Transaktionen.

Für die Instrumentierung von Java-Anwendung mit Prometheus-Metriken gibt es grundsätzlich zwei Möglichkeiten:

  1. Die direkte Instrumentierung mit der Prometheus Client Library für Java ist die einfachste Art, Java-Code für Prometheus zu instrumentieren.
  2. Mapping von 3rd-Party-Metriken nach Prometheus: Falls es nicht möglich ist, die Prometheus-Client-Bibliothek direkt zu nutzen – beispielsweise wenn das Projekt einen anderen Mechanismus zur Instrumentierung nutzt oder sich der Quelltext nicht ändern lässt – steht eine Vielzahl von Bibliotheken bereit, um 3rd-Party-Metriken für Prometheus aufzubereiten.

In den folgenden Abschnitten werden die beiden Möglichkeiten zur Instrumentierung von Java-Anwendungen vorgestellt.

Direkte Instrumentierung

Die Java-Bibliothek zur Instrumentierung für Prometheus lässt sich als einfache Maven-Dependency einbinden:

<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient_common</artifactId>
<version>0.0.16</version>
</dependency>

Die Metriken werden im Code einfach über statische Builder-Methoden erzeugt. Hier ein Beispiel für eine Counter-Metrik:

private final Counter counter = Counter.build()
.name("requests_total")
.help("Total number of requests.")
.register();

Die Java-Client-Bibliothek stellt vier Arten von Metriken zur Verfügung, die sich im Java-Code verwenden lassen:

  • Counter: einfache Zähler, etwa für die Anzahl von Aufrufen auf einer REST-URL. Ein Counter kann nur inkrementiert werden, der aktuelle Wert kann niemals kleiner sein als der vorherige Wert. Wenn die Applikation neu gestartet wird und der Counter dadurch wieder bei 0 anfängt, erkennt der Prometheus-Server das und gleicht die Differenz intern aus, sodass Neustarts bei der Auswertung kein Problem darstellen.
  • Gauge: eine Zahl, die sich beliebig nach oben und unten ändern kann, beispielsweise die Anzahl der gerade laufenden Instanzen in einer Cluster-Umgebung.
  • Histogram, Summary: Diese Metriken fassen statistische Informationen zusammen, etwa über die Dauer der Bearbeitung von HTTP-Requests. Ein Histogramm beantwortet Fragen wie "Wie viele Aufrufe dauern länger als 100 ms?", während eine Summary die Frage beantwortet "Welche Antwortzeit können wir für 95 % der Anfragen garantieren?". Der Unterschied zwischen Histogrammen und Summaries steckt im Detail, teilweise eignen sich auch beide Typen für dieselbe Metrik. Eine ausführliche Gegenüberstellung von Summaries und Histogrammen findet sich in der Rubrik Best Practices der Prometheus-Dokumentation.

Die Prometheus-Client-Bibliothek stellt eine Prometheus-Registry bereit, die als Singleton implementiert ist und Referenzen auf alle Metriken verwaltet. Im Code-Beispiel oben wird mit dem Aufruf von register() die Counter-Metrik in der Registry registriert.

Um die Metriken aus der Prometheus-Registry über einen HTTP-Aufruf verfügbar zu machen, kann man mit der Methode TextFormat.write004() den Inhalt aller Metriken in einen Output-Stream serialisieren:

TextFormat.write004(responseWriter, CollectorRegistry.
defaultRegistry.metricFamilySamples());

Der responseWriter gehört zur HTTP-Response, die an den Prometheus-Server übertragen wird. Das HTTP-Response-Objekt wird je nach eingesetztem Framework (Servlet, JAX-RS etc.) auf unterschiedliche Arten bereitgestellt.

Instrumentierung mit 3rd-Party-Metriken

Viele Applikationen verwenden bereits Tools, um Metriken bereitzustellen. In dem Fall ist es nicht nötig, die Prometheus-Client-Bibliothek parallel zu den bestehenden Tools einzubauen. Vielmehr ist es in den meisten Fällen möglich, die Metriken für Prometheus verfügbar zu machen. Hierfür stehen im GitHub Repository der Prometheus Client Library für Java entsprechende Implementierungen zur Verfügung.

Spring Boot Actuators

Spring Boot bringt das Actuator-Framework mit, um Anwendungen zu instrumentieren und Metriken bereitzustellen. Die Java-Client-Bibliothek für Prometheus implementiert eine Klasse SpringBootMetricsCollector, die Actuator-Metriken in Prometheus-Metriken konvertiert. Über die Annotation @EnablePrometheusEndpoint werden dann die Prometheus-Metriken bereitgestellt.

JMX

Wer Java-EE-konforme Serverapplikationen schreibt, kommt um den JMX-Standard (Java Management Extensions) nicht herum. Um Metriken über eine bestehende JMX-Applikation für Prometheus zur Verfügung zu stellen, kann man den jmx_exporter verwenden. Das ist ein externes Programm, das die JMX Beans ausliest, die entsprechenden Daten in Prometheus-Metriken konvertiert und dann bereitstellt. Der jmx_exporter wird entweder als eigenständige Applikation betrieben, die auf die JMX Beans zugreift, oder als Agent innerhalb der bestehenden JVM. In beiden Fällen braucht der Quellcode der Java-Applikation nicht geändert zu werden.

Das Prometheus-Monitoring von JMX-Applikationen hat gewisse Grenzen. Beispielsweise sind die Datenmodelle von JMX und Prometheus nicht 100 Prozent kompatibel: JMX ermöglicht es, beliebige Daten bereitzustellen, während Prometheus nur Fließkommazahlen verarbeitet. Es lassen sich also nicht alle JMX-Informationen in Prometheus übernehmen. Außerdem kann das Auslesen aller JMX Beans zeitaufwendig sein, insbesondere wenn die JMX Beans ihrerseits Metriken "on the fly" akquirieren. Deshalb sollte beim Einsatz des jmx_exporter mithilfe von Black- oder Whitelists festgelegt werden, welche Beans geladen werden. Berücksichtigt man diese Einschränkungen, ist der jmx_exporter eine gute Möglichkeit, Legacy-Java-Applikationen in Prometheus-Monitoring-Infrastrukturen einzubinden.

Weitere Frameworks

Neben den großen Frameworks Spring und Java EE gibt es noch eine Vielzahl kleinerer Frameworks, die ebenfalls Instrumentierung anbieten. Einige davon werden von der Prometheus Client Library für Java unterstützt. Als Beispiel sei hier die Dropwizard Metrics Library genannt. Die Client-Bibliothek bietet hierfür die Klasse DropwizardExports, die Dropwizard-Metriken für Prometheus exportiert. Auch für weitere Libraries stehen in den Java Client Bridges zur Verfügung, es lohnt sich daher einen Blick in die Subprojekte zu werfen.