Ein bisschen Nachsicht bitte! Anwendungsstabilität mit MicroProfile Fault Tolerance

MicroProfile (https://microprofile.io/) enthält u. a. den Baustein MP Fault Tolerance, mit dem auf sehr einfache Weise die bekannten Stability Patterns in JEE/MicroProfile-Anwendungen eingebaut werden können.

Bei verteilten Anwendungen (Microservices) – aber nicht nur dort – können Fehler durch nicht erreichbare oder nicht funktionierende Anwendungsteile entstehen. Soll dann nicht wie bei einem Dominoeffekt die Gesamtanwendung betroffen sein, muss der aufrufende Teil resilient sein, d. h. durch Wiederholungen oder Ersatzaufrufe zu einem verträglichen Ergebnis kommen.

MP Fault Tolerance enthält Interzeptoren mit den im Folgenden beschriebenen Bindings, mit denen im Fehlerfall gewünschte Ausweichaktionen initiiert werden können.

Nochmals probieren

@Retry führt beim Auftauchen einer Exception zum wiederholten Aufruf der Methode:

@Retry(maxRetries = 4)
public int doSomethingWithRetry() {

Mit diversen Parametern von @Retry kann bestimmt werden, welche Exceptions die Wiederholungen auslösen sollen, wie lange oder wie oft es versucht werden soll und welche Wartezeit zwischen den Wiederholungen eingehalten werden soll.

Programmierte Ungeduld

Mit @Timeout kann eine Obergrenze für die Ausführungszeit einer Methode angegeben werden:

@Timeout(1000)
public int doSomethingWithTimeout() {

Rückstellende Sicherung

Circuit Breaker ist ein Pattern, das bei zu häufigen Fehlern (=Exceptions) „den Schalter öffnet“, d. h. die betroffene Methode für eine gewisse Zeit nicht mehr aufruft und statt dessen eine dementsprechende Exception wirft. Nach Ablauf der Wartezeit wird der Schalter probeweise wieder geschlossen.

MP Fault Tolerance bietet dazu @CircuitBreaker an:

@CircuitBreaker(failureRatio = 0.25, requestVolumeThreshold = 10)
public int doSomethingWithCircuitBreaker() {

Mit Parametern kann bestimmt werden, was „zu häufig“ sein soll und wann der Schalter nach Öffnung wieder geschlossen wird.

Ersatzhandlung

Sind Fehler (=Exceptions) für den Aufrufer nicht OK, kann mit @Fallback eine Ersatzaktion definiert werden:

@Fallback(fallbackMethod = "return42")
public int doSomethingWithFallback() {
  ...
}

private int return42() {
  return 42;

Plattformen

MicroProfile Fault Tolerance wird u. a. von folgenden JEE-Servern unterstützt:

  • OpenLiberty (mit aktiviertem Feature mpFaultTolerance-2.0).
  • Payara.

WildFly wird MP Fault Tolerance voraussichtlich ab der Version 19 unterstützen

Die genannten Annotationen befinden sich bspw. in der Maven-Dependency org.eclipse.microprofile.fault-tolerance:microprofile-fault-tolerance-api (derzeit in Version 2.0).

Demo

In https://github.com/GEDOPLAN/microprofile-demo/tree/master/microprofile-fault-tolerance finden Sie ein Beispielprojekt mit einem Service, der die oben gezeigten Annotationen enthält und über Rest Endpoints aufgerufen werden kann. Die Anwendung kann als WAR-File auf einen der genannten Server deployt werden. Alternativ können über vorkonfigurierte Maven-Profile Docker-Images zum direkten Ausprobieren erstellt werden.

Bis bald – vielleicht auch in einem unserer Trainings in Berlin, Frankfurt, Bielefeld, Köln oder bei Ihnen!

Schauen Sie sich doch mal unseren neuen Kurs zum Thema an: JEE und MicroProfile mit Quarkus

Immer noch gesund? Änderungen von MicroProfile Health 2.0 vs. 1.0

In meinem Post https://javaeeblog.wordpress.com/2019/01/27/alles-gesund-health-checking-mit-microprofile-health habe ich einen Überblick über MicroProfile Health in der Version 1.0 gegeben. Mittlerweile ist die Version 2.0 erschienen (als Teil von MicroProfile 3.0), woduch einige – teilweise inkompatible – Änderungen einhergehen:

  • Die Prüfungen werden nun in Tests der Verfügbarkeit (Liveness) und Bereitschaft (Readiness) unterteilt, um so besser die Anforderungen von Container-Infrastrukturen zu unterstützen (vgl. entsprechende Probes in Kubernetes). Statt des bisherigen Qualifiers @Health werden nun @Live bzw. @Ready zur Definition von HealthCheck-Beans verwendet:
    @ApplicationScoped
    @Liveness
    public class LivenessCheck implements HealthCheck {
    
      @Override
      public HealthCheckResponse call() {
        return HealthCheckResponse
            .named("Service1")
            .up()
            .build();
    

    @Health steht noch zur Verfügung, ist aber deprecated.

  • Die neuen Endpunkte /health/live und /health/ready veröffentlichen den Zustand von Liveness bzw Readiness:
    GET /health/live
    
    200 OK
    {
      "status": "UP",
      "checks": [{
        "name": "Service1",
        "status": "UP"
      }]
    }
    

    Der bisherige Endpunkt /health existiert weiterhin.

  • Im JSON-Format wurden die Attribute outcome und state durch status ersetzt.

Ausblenden von Default-Checks in MicroProfile Health 2.1

Die Implementierung von Healthchecks als CDI-Beans ermöglicht es, dass auch Plattform-Implementierungen/Bibliotheken Prüfergebnisse bereitstellen (bspw. ein DB Connection Pool). Setzt man die neue MicroProfile Configuration Property mp.health.disable-default-procedures auf true, werden solche Default-Checks nicht aktiviert, d. h. im Response der o. a. Endpoints befinden sich nur von der Anwendung selbst bereitgestellte Werte.

Demo

Ich habe das Beispielprojekt mit anderen MicroProfile-Demos kombiniert in https://github.com/GEDOPLAN/microprofile-demo eingecheckt. Im Verzeichnis microprofile-health finden Sie ein Demoprojekt mit zwei Health Checks, deren Ergebnis über eine Webseite beeinflusst werden kann. Die Anwendung kann als WAR-File auf einen Server mit Unterstützung von MicroProfile 3.0 deployt werden. Alternativ können über vorkonfigurierte Maven-Profile Docker-Images zum direkten Ausprobieren erstellt werden.

Bis bald – vielleicht in einem unserer Trainings in Berlin, Bielefeld, Köln oder bei Ihnen!
https://gedoplan-it-training.de/

Welche Einstellung haben Sie? Anwendungskonfiguration mit MicroProfile Config

MicroProfile (https://microprofile.io/) enthält u. a. den Baustein Microprofile Config, mit dem JEE-Anwendungen aus verschiedenen Quellen heraus Konfigurationsparameter erhalten können. Neben einem API stehen auch Injektionsmöglichkeiten zur Verfügung.

Configuration API

MicroProfile Config ist durch Vorläufer-Projekte wie Apache Tamaya oder DeltaSpike Config beeinflusst und besitzt diverse Implementierungen wie SmallRye Config im WildFly. Zum portablen Zugriff auf den konkreten Provider dient die Klasse ConfigProvider und das Interface Config. Im einfachsten Fall kann ein Konfigurationswert so erfragt werden:

Config config = ConfigProvider.getConfig();
String value = config.getValue("java.version", String.class);

Config Sources

Die Konfigurationswerte werden diesen Quellen entnommen (in absteigender Priorität):

  • System Properties
  • Environment Variables
  • Classpath resource(s) META-INF/microprofile-config.properties

Nach Wunsch können die Prioritäten angepasst und zusätzliche Konfigurationsquellen ergänzt werden.

Injektion von Konfigurationswerten

Für die bequeme Nutzung in CDI Beans steht der Qualifier @ConfigProperty zur Verfügung:

@Inject
@ConfigProperty(name = "answer")
int answer;

Sollte eine solche Property-Referenz nicht befriedigt werden, d. h. sollte es im konkreten Beispiel keinen konfigurierten Wert mit dem Namen answer geben, schlägt das Deployment der Anwendung fehl. Ist das nicht erwünscht, kann als Injektionsziel ein Optional genutzt werden:

@Inject
@ConfigProperty(name = "HOME")
Optional home;

Plattformen

MicroProfile Config wird u. a. von folgenden JEE-Servern unterstützt:

  • OpenLiberty (mit aktiviertem Feature mpConfig-1.3).
  • Payara.
  • WildFly.

Die genannten Klassen befinden sich bspw. in der Maven-Dependency org.eclipse.microprofile.config:microprofile-config-api (derzeit in Version 1.3).

Demo

In https://github.com/GEDOPLAN/microprofile-demo/tree/master/microprofile-config finden Sie ein Beispielprojekt mit einem REST-Service, der API-Nutzung und Injektionsmöglichkeiten zeigt. Die Anwendung kann als WAR-File auf einen der genannten Server deployt werden. Alternativ können über vorkonfigurierte Maven-Profile Docker-Images zum direkten Ausprobieren erstellt werden.

Bis bald – vielleicht auch in einem unserer Trainings in Berlin, Bielefeld, Köln oder bei Ihnen!
https://gedoplan-it-training.de/

Wie läuft’s denn so? Monitoring mit MicroProfile Metrics

In meinem Blog-Eintrag „Alles gesund? Health checking mit MicroProfile Health“ habe ich dargestellt, wie einfach man den Gesundheitszustand einer Anwendung auf Basis von MicroProfile Health veröffentlichen kann. Und wenn man nun nicht nur wissen möchte, ob ein Service läuft, sondern mehr Details über den Service-Zustand erfahren möchte? Dann unterstützt uns ein weiterer Baustein: MicroProfile Metrics.

Telemetriedaten out of the box

Über den Rest-Endpoint /metrics/base werden ohne weiteren Programmieraufwand Basis-Telemetriedaten zur Verfügung gestellt:

{
  "memory.maxHeap": 8342470656,
  "memory.usedHeap": 259349504,
  "gc.G1 Young Generation.count": 28,
  "cpu.systemLoadAverage": 0.6,
  "thread.count": 111,
  ...
}

Die Daten werden in JSON geliefert, wenn man sie mit diesem Media Type anfordert (z. B. curl -H "Accept: application/json" localhost:8080/metrics/base). Mit dem Default-Media-Type text/plain werden die Daten passend für die Verarbeitung in Prometheus geliefert.

Der Endpoint /metrics/vendor ist für herstellerspezifische Messdaten aus der genutzten Plattform vorgesehen.

Anwendungsspezifische Metriken

EE-Anwendungen können weitere Messdaten bereitstellen. So kann man bspw. Methoden von CDI Beans mit der Annotation @Gauge versehen:

  @Gauge(name = "answerToLifeUniverseAndEverything", absolute = true, unit = MetricUnits.NONE)
  public long getAnswerToLifeUniverseAndEverything() {
    return 42;
  }

Die derart zur Verfügung gestellten Werte werden im Endpoint /metrics/application veröffentlicht:

{
  "answerToLifeUniverseAndEverything": 42
}

Neben dieser Möglichkeit, eigene Messwerte zu berechnen und zu veröffentlichen, kann man auch Telemetriedaten durch das Framework aggregieren lassen:

  @GET
  @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
  @Timed(name = "personList", absolute = true)
  public List getAll() {
    return this.personRepository.findAll();
  }

@Timed bewirkt hier, dass die Ausführungszeiten der annotierten Methode gemessen und zu verschiedenen statistischen Werten aggregiert werden:

{
  "personList": {
    "p50": 4922800.0,
    "p75": 5160200.0,
    "p95": 1.00322E7,
    "p98": 1.00322E7,
    "p99": 1.00322E7,
    "p999": 1.00322E7,
    "min": 3218000.0,
    "mean": 5476794.800597489,
    "max": 1.00322E7,
    "stddev": 2340795.005960796,
    "count": 5,
    "meanRate": 0.6766077577220262,
    "oneMinRate": 1.0,
    "fiveMinRate": 1.0,
    "fifteenMinRate": 1.0
  }
}

Analog könnte mit @Counted ein Aufrufzähler für eine Methode etabliert werden.

Gesamt-Metrik

Der Endpoint /metrics fasst die bislang genannten Datengruppen in ein Gesamtergebnis zusammen.

Plattformen

MicroProfile Metrics wird u. a. von folgenden JEE-Servern unterstützt:

  • OpenLiberty (mit aktivierten Features mpMetrics-1.1 und monitor-1.0).
  • Payara.
  • WildFly (Achtung: WildFly hat unterschiedliche Ports für Applikations- und Management-Zugriffe, im Default 8080 und 9990. Der o. a. REST-Endpoint /metrics steht über den Management-Port zur Verfügung).

Die genannten Klassen befinden sich bspw. in der Maven-Dependency org.eclipse.microprofile:microprofile.

Demo

In https://github.com/GEDOPLAN/metrics-demo finden Sie ein Beispielprojekt mit einem REST-Service, dessen GET– und POST-Methoden so annotiert sind, dass Zeiten bzw. Aufrufzahlen gemessen werden. Der o. a. Service, der die legendäre 42 als Ergebnis liefert, ist ebenfalls im Beispielprojekt enthalten. Die Anwendung kann als WAR-File auf einen der genannten Server deployt werden. Alternativ können über vorkonfigurierte Maven-Profile Docker-Images zum direkten Ausprobieren erstellt werden.

Bis bald – vielleicht auch in einem unserer Trainings in Berlin, Bielefeld, Köln oder bei Ihnen!
https://gedoplan-it-training.de/