JavaMonitoring

Performance Monitoring mit Annotations und Prometheus

Die Überwachung der Anwendungsleistung ist entscheidend in der modernen Softwareentwicklung. In diesem Blog-Artikel zeige ich dir das Performance Monitoring durch die Messung der Ausführungsdauer von Methoden in einer Spring Boot-Anwendung. Wir verwenden dazu benutzerdefinierte Annotations, AOP und Prometheus.

Patrick Robert Doyle

Vorausgesetzter Tech-Stack

  • Spring Boot-Anwendung (hier gebaut mit Maven)
  • Prometheus als Monitoring-Tool
  • Grafana für die Darstellung der Daten

Implementierung

1. Abhängigkeiten hinzufügen

Füge die Abhängigkeiten für den Spring Boot Actuator, AOP und Micrometer in deine pom.xml ein.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

2. Prometheus Endpoint freigeben

In deiner application.properties füge gegebenenfalls die folgende Zeile hinzu, um den Endpunkt /actuator/prometheus zu aktivieren, sodass Prometheus die Metriken hier abrufen kann.

management.endpoints.web.exposure.include=prometheus

3. Annotation TimedMethod erstellen

Erstelle eine benutzerdefinierte Annotation namens TimedMethod. Diese Annotation ermöglicht es dir, spezifische Methoden für die Zeitmessung zu markieren.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TimedMethod {
        String value() default "";
}

4. Aspect TimingAspect erstellen

Implementiere danach einen Aspect, der die annotierten Methoden abfängt. Die Klasse verwendet Spring’s AOP (Aspect-Oriented Programming) und Micrometer, um die Ausführungszeit der Methode zu messen. Es empfiehlt sich, den Namen der Anwendung als Prefix hinzuzufügen.

@Aspect
@Component
public class TimingAspect {
    private final MeterRegistry meterRegistry;

    public TimingAspect(MeterRegistry meterRegistry) {this.meterRegistry = meterRegistry;}

    @Around("@annotation(TimedMethod)")
    public Object timeMethod(ProceedingJoinPoint pjp) {
        final var methodName = "performance-monitoring_method_" + pjp.getSignature().getName();
        final var timer = Timer.builder(methodName).description("Total time of " + 
                                                   pjp.getSignature().getName() + " method").register(meterRegistry);

        try {
            return timer.recordCallable(() -> {
                try {
                    return pjp.proceed();
                } catch (Throwable t) {
                    // Handle or log the exception as needed
                    throw new RuntimeException(t);
                }
            });
        } catch (Exception e) {
            // Handle or log the exception as needed
            throw new RuntimeException(e);
        }
    }
}

5. Methoden annotieren

Die @TimedMethod-Annotation kann jetzt zu den Methoden ergänzt werden, die du überwachen willst.

@TimedMethod
public void foo() {
    // ...
}

@TimedMethod
public void bar() {
    // ...
}

6. Prometheus Ausgabe

Nachdem du deine Anwendung gestartet hast, sollten die benutzerdefinierten Metriken unter dem Prometheus-Endpunkt http://localhost:8080/actuator/prometheus verfügbar sein. Die Ausgabe könnte so aussehen:

# HELP performance_monitoring_method_foo_seconds Total time of foo method
# TYPE performance_monitoring_method_foo_seconds summary
performance_monitoring_method_foo_seconds_count 8.0
performance_monitoring_method_foo_seconds_sum 27.0449213
# HELP performance_monitoring_method_foo_seconds_max Total time of foo method
# TYPE performance_monitoring_method_foo_seconds_max gauge
performance_monitoring_method_foo_seconds_max 5.0034022
# HELP performance_monitoring_method_bar_seconds Total time of bar method
# TYPE performance_monitoring_method_bar_seconds summary
performance_monitoring_method_bar_seconds_count 7.0
performance_monitoring_method_bar_seconds_sum 49.035802
# HELP performance_monitoring_method_bar_seconds_max Total time of bar method
# TYPE performance_monitoring_method_bar_seconds_max gauge
performance_monitoring_method_bar_seconds_max 10.0017256

Da das Performance Monitoring für zwei Methoden erfolgt, sehen wir auch zwei Blöcke an Metriken.

Füge diese Metriken zu deinem Grafana-Dashboard hinzu, um sie zu überwachen und in verschiedenen Graphen anzuzeigen.

Beispielprojekt

Das ausführbare Beispielprojekt mit sämtlichem Code ist hier zu finden: https://gitlab.com/pep-digital/blog/performance-monitoring

Zusammenfassung

Dieser Blog-Beitrag hat gezeigt, wie die Performance von Methoden in einer Spring Boot-Anwendung effektiv überwacht werden können. Natürlich kann die Implementierung an verschiedenen Stellen noch ausgebaut werden.

Neben Timern bietet Micrometer außerdem eine Reihe weiterer Metrik-Typen, die in Spring Boot Anwendungen genutzt werden können:

  1. Counter: Ein einfacher Zähler, der nur inkrementiert werden kann. Häufig verwendet für die Zählung von Anfragen, Aufgaben, Fehlern usw.
  2. Gauge: Ein Messwert, der den aktuellen Wert eines bestimmten Objekts oder einer Variable anzeigt.
  3. Distribution Summary: Ähnlich wie ein Timer, aber für die Messung von nicht-zeitbezogenen Verteilungen wie Dateigrößen, Punktzahlen usw.
  4. Long Task Timer: Für die Messung von lang laufenden Aufgaben, die parallel zu anderen Aufgaben laufen können.
  5. Function Counter: Ein Counter, der den Wert einer Funktion über die Zeit hinweg inkrementiert.
  6. Function Gauge: Ein Gauge, der den Wert einer Funktion auswertet, wenn der Wert abgerufen wird.
  7. Time Gauge: Ein Gauge, der die Zeit in Sekunden misst, die eine Funktion zum Ausführen benötigt.
  8. Meter: Ein allgemeiner Typ für andere benutzerdefinierte Metriken, der mehrere Messungen gleichzeitig darstellen kann.

Diese verschiedenen Metrik-Typen ermöglichen eine umfassende Überwachung und Analyse des Verhaltens von Spring Boot Anwendungen.

Mit Spring Boot, Micrometer, benutzerdefinierten Annotations und Prometheus hast du auf jeden Fall eine starke Lösung für das Performance-Monitoring an der Hand!