1. Einleitung
Prometheus ist ein Open-Source-Tool zur Überwachung von Systemen und Anwendungen. Es sammelt regelmäßig Messwerte (Metriken), etwa zur CPU-Auslastung, Anzahl von Anfragen oder Speichernutzung.
Diese Daten speichert Prometheus in einer Zeitreihendatenbank. So kann man sehen, wie sich bestimmte Werte im Zeitverlauf verändern. Mit der eigenen Abfragesprache PromQL lassen sich die Daten gezielt auswerten.
1.1. Welches Problem löst Prometheus?
Moderne Software-Systeme bestehen oft aus vielen kleinen Diensten (Microservices), die dynamisch in Containern laufen. In dieser komplexen Umgebung wird es schwierig, den Überblick über den Zustand der Systeme zu behalten:
-
Läuft alles wie erwartet?
-
Warum ist die Anwendung plötzlich langsam?
-
Gibt es Fehlermuster, bevor ein Absturz passiert?
Prometheus löst genau dieses Problem: Es sammelt regelmäßig präzise Messdaten über den Zustand und das Verhalten einer Anwendung. So kann man Fehler früh erkennen, Engpässe analysieren und Systeme effizienter betreiben.
2. Warum Prometheus?
Prometheus ist besonders beliebt, weil es einige wichtige Vorteile mitbringt:
-
Einfach zu integrieren: Man muss nur einen Endpoint bereitstellen, an dem Prometheus regelmäßig Messwerte abfragen kann.
-
Eigene Abfragesprache (PromQL): Ermöglicht sehr gezielte Auswertungen.
-
Gute Visualisierung mit Grafana: Daten können übersichtlich in Dashboards dargestellt werden.
3. Architektur von Prometheus

-
Prometheus-Server: Fragt regelmäßig Metriken ab und speichert sie.
-
Exporters / Jobs: Stellen Metriken unter
/metrics
bereit. -
Pushgateway: Unterstützt kurzlebige Jobs, die Metriken einmalig senden.
-
Service Discovery: Erkennt automatisch neue Dienste (z. B. in Kubernetes).
-
Alertmanager: Versendet Warnungen auf Basis definierter Regeln.
-
Grafana: Visualisiert Metriken in Dashboards.
-
Web UI: Interface für direkte PromQL-Abfragen.
4. Prometheus vs. Micrometer
Prometheus und Micrometer haben unterschiedliche Rollen im Monitoring-Stack, auch wenn sie oft zusammen verwendet werden:
Aspekt | Beschreibung |
---|---|
Prometheus |
Monitoring-System zur Erfassung, Speicherung und Analyse von Metriken. Es holt sich die Daten (Pull-Prinzip) regelmäßig von Endpunkten wie |
Micrometer |
Bibliothek für Anwendungen zur Erzeugung von Metriken. Sie abstrahiert verschiedene Monitoring-Systeme (z. B. Prometheus, InfluxDB, Datadog) und bietet eine einheitliche API. |
Zusammenarbeit |
Micrometer erzeugt die Metriken innerhalb einer Anwendung (z. B. Quarkus-App). Prometheus sammelt diese Metriken dann regelmäßig ein. |
Micrometer ist also ein Produzent, während Prometheus ein Sammler und Analysator ist.
5. Weitere Monitoring-Alternativen (kurzer Überblick)
Tool | Kurzbeschreibung |
---|---|
Grafana Cloud |
Gehostete Monitoring-Lösung, integriert Prometheus, Loki und Tempo. Eher für schnelle Setups oder SaaS-Szenarien. |
Datadog |
Kommerzielle Lösung mit starker Integration in Cloud-Umgebungen, bietet Metriken, Logs und Tracing. |
InfluxDB |
Zeitreihendatenbank mit eigener Query-Sprache (Flux). Eignet sich für Metriken und Events. |
Zabbix |
Klassisches Monitoring-Tool mit Fokus auf Infrastrukturüberwachung, eher agentenbasiert. |
New Relic |
Komplettlösung für Application Performance Monitoring (APM), eher für größere Enterprise-Setups gedacht. |
OpenTelemetry |
Standard zur Sammlung von Logs, Metriken und Traces – ersetzt langfristig viele eigene APIs (wie Micrometer) und ist stark im Kommen. |
6. Prometheus in Quarkus
Quarkus bietet eine integrierte Unterstützung für Micrometer und Prometheus. Die Metriken werden unter /q/metrics
bereitgestellt. Voraussetzung dafür ist die Erweiterung quarkus-micrometer-registry-prometheus
.
6.1. Konfiguration in Quarkus
quarkus.micrometer.export.prometheus.enabled=true
quarkus.micrometer.export.prometheus.path=/q/metrics
Beispiel für prometheus.yml
:
scrape_configs:
- job_name: 'quarkus-app'
static_configs:
- targets: [ 'quarkus:8080' ]
Mögliche Konfiguration in der docker-compose.yml
:
services:
prometheus:
image: prom/prometheus:latest
container_name: prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"
restart: always
networks:
- monitoring
quarkus:
build:
context: ../../../
dockerfile: ./src/main/docker/Dockerfile.jvm
container_name: quarkus
ports:
- "8080:8080" # Optional, for host access
restart: always
networks:
- monitoring
networks:
monitoring:
driver: bridge
Die services müssen im selben Netzwerk sein, damit Prometheus die Metriken abfragen kann. |
6.2. Eigene Metriken in Resource-Klassen
Mit dem MeterRegistry
lassen sich benutzerdefinierte Metriken erzeugen:
package at.htl.feature;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tags;
import io.micrometer.core.instrument.Timer;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import java.util.LinkedList;
@ApplicationScoped
@Path("/person")
@Produces(MediaType.APPLICATION_JSON)
public class PersonResource {
@Inject
MeterRegistry registry;
private LinkedList<String> list = new LinkedList<>();
@Inject
PersonRepository personRepository;
public PersonResource(MeterRegistry registry) {
this.registry = registry;
registry.gaugeCollectionSize("person_list_size", Tags.empty(), list);
}
// Counter für die Anzahl der Anfragen
@GET
@Path("/counter/check/{input}")
public boolean checkPersonCounter(@PathParam("input") String input) {
list.add(input);
registry.counter("person_counter").increment();
return getPerson(input);
}
// Timer für die Zeitmessung
@GET
@Path("/timer/check/{input}")
public boolean checkPersonTimer(@PathParam("input") String input) {
list.add(input);
Timer.Sample sample = Timer.start(registry);
boolean result = getPerson(input);
sample.stop(registry.timer("person_timer"));
return result;
}
// Method to check if a person exists in the database
public boolean getPerson(String input) {
String[] parts = input.split(",");
if (parts.length != 2 || input.isEmpty()) {
return false; // Input format is not correct
}
String name = parts[0].trim();
int age = Integer.parseInt(parts[1].trim());
// Check if the person exists in the repository
Person person = (Person) personRepository.find("p_name = ?1 and p_age = ?2", name, age);
return person != null; // Return true if person exists, false otherwise
}
@DELETE
@Path("/clear-list")
public void clearList() {
list.clear();
}
}
Diese Metriken erscheinen dann automatisch im /q/metrics
-Output.