Hystrix: Fehlertoleranz statt Hochverfügbarkeit – Eine Einführung in Resilience mit Hystrix

Keine Kommentare

Der Herr, der eben beim Auspacken seines Laptops beinahe meinen Kaffeebecher umgestoßen hat, schaut kurz auf meinen Bildschirm und sieht den geöffneten Hystrix-Vortrag. Ja, von Hystrix hat er schon einmal gehört, hat sein Team ihm vorgeschlagen, soll gut funktionieren. Doch dann holt er Luft für sein großes Aber: “Warum sollte ich meinen Entwicklern Zeit dafür geben ein Framework einzuführen, das ihnen hilft auf Ausfälle und Fehler zu reagieren? Ich möchte, dass sie in der Zeit stattdessen verhindern, dass diese Fehler überhaupt auftreten”.

Ich vermute, dass ich wohl erst nach Göttingen an dem Vortrag weiter arbeiten kann, klappe den Rechner zu und beginne zu erzählen: In komplexen verteilten Systemen sind Ausfälle und Fehler immanent; Systeme, die nicht fehlertolerant sind, werden keine zufriedenstellende User-Experience bieten können. Der Einsatz von Hystrix sensibilisiert Entwickler beim Einbinden von externen Diensten über den möglichen Einfluss auf das eigene System nachzudenken.

In verteilten Systemen addieren sich die Ausfallzeiten: Angenommen das Team meines Sitznachbarn schafft es, dass jeder Service zu 99,99% erreichbar ist, also deutlich unter 5 Minuten Downtime pro Monat hat. Wenn man dann weiter annimmt, dass ihre Microservice-Architektur aus 30 unabhängigen Services besteht, dann werden nur noch zu 99,7% der Zeit alle Services verfügbar sein – oder anders gesagt: Fast zweieinviertel Stunden pro Monat, ist nicht das komplette System verfügbar. Sind die Services nicht verfügbar oder fehlerhaft, sind die Kunden unzufrieden und man verdient kein Geld mit ihnen – kurzum: die Software ist wertlos.

Die oben skizzierte Erkenntnis führt zu dem Mantra der Resilience-Bewegung: “Do not try to avoid failures. Embrace them”. Wer mehr Details über die Grundlagen von Resilience und Resilient Software Design erfahren möchte, sei auf die gute Resilience-Einführung oder den Talk über Resilience-Patterns von Uwe Friedrichsen verwiesen.

Wir wollen also mit den Fehlern umgehen, anstatt zu versuchen, sie zu vermeiden. Eine Technologie um diese sogenannte Resiliance zu erreichen ist Hystrix, ein Java-Framework aus dem Netflix Open Source Stack. Die Entkopplung einzelner Services in verteilten Systemen ist die Kernaufgabe von Hystrix; und damit der Aufbau eines robusten und fehlertoleranten Systems.

Die wichtigsten Eigenschaften von Hystrix

hystrix-features

 

  • Alle Aufrufe von externen Systemen werden in HystrixCommands verpackt, welche typischerweise in einem separaten Thread ausgeführt werden.
  • Aufrufe werden abgebrochen, wenn sie mehr Zeit brauchen als vorab als Obergrenze festgelegt wurde. Es muss also z.B. nicht mehr auf Netzwerk- oder Datenbank-Timeouts gewartet werden, bis eine Programmausführung fortgesetzt werden kann.
  • Für jede externe Abhängigkeit wird ein eigener kleiner Thread-Pool verwaltet. Damit wird verhindert, dass eine einzelne fehlerhafte Abhängigkeit ein ganzes System non-responsive machen kann.
  • Die Ausführungszeiten, Erfolge und Fehler eines jeden HystrixCommands werden gemessen, erfasst und in einem Dashboard zur Verfügung gestellt.
  • Ein circuit-breaker stoppt alle Aufrufe einer externen Abhängigkeit, die derzeit nicht erreichbar oder fehlerhaft ist. 
  • Es können Fallback-Logiken implementiert werden, für den Fall, dass externe Abhängigkeiten keine oder fehlerhafte Antworten liefern.

Hello World mit Hystrix

Nach der Einführung in die grundlegenden Konzepte von Hystrix wird es Zeit für ein Beispiel:

public class CommandHelloWorld extends HystrixCommand {
 
   private final String name;
 
   public CommandHelloWorld(String name) {
     super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
     this.name = name;
    }
 
   @Override
   protected String run() {
     //network call
     return getLocalizedGreeting(name);
    }
 
   @Override
   protected String getFallback() {
     //graceful degradation - use english as fallback
     return "Hello " + name + "!";
    }
 
    [...]
 }

Der obige Code zeigt ein einfaches HystrixCommand, das versucht eine entferne Ressource aufzurufen um eine Begrüßung in der Sprache des Nutzers abzurufen. Sollte der Aufruf fehlschlagen, so wird als Fallback eine englische Begrüßung ausgegeben. Ein HystrixCommand kann synchron, asynchron oder mit dem Observer-Pattern ausgeführt werden:

1) Synchrone Ausführung

 String s = new CommandHelloWorld("World").execute();

2) Asynchrone Ausführung

 Future fs = new CommandHelloWorld("World").queue();
 String s = fs.get();

3) Observer-Pattern

 Observable fWorld = new CommandHelloWorld("World").observe();
 fWorld.subscribe((v) -> {
   System.out.println("onNext: " + v);
 })

Die Wiki-Dokumentation des Hystrix-Projektes ist umfangreich und gut verständlich. Daher verzichte an dieser Stelle auf weitere Einstiegsbeispiele und verweise stattdessen auf das originale Tutorial bei GitHub.

Konfiguration und Metriken

Hystrix ist schnell eingebaut, aber es gibt doch eine gewisse Lernkurve, die man einplanen sollte. Zum Beispiel für die Konfiguration: Die Möglichkeiten der Konfiguration sind umfangreich. Der Ansatz von Netflix ist es, die Kommandos in der Standardkonfiguration zu starten und dann im Betrieb zu messen, beobachten und feinzujustieren. Dafür braucht man zwingend dynamische Konfiguration und jemanden, der das Hystrix-Dashboard im Auge behält.

Auch langfristig sollte man die Metriken von Hystrix überwachen und die sehr umfangreichen Informationen nicht ungenutzt lassen. So kann man zum Beispiel die Hystrix Streams, bzw. deren aggregierte Informationen, in Elasticsearch speichern und langfristig aus den Metriken lernen

Neues und Ausblick auf Hystrix 2.0

Das aktuelle Hystrix-Release 1.5 beinhaltet Erweiterungen im Bereich der Metriken. Die Metric-Streams werden nun auch unaggregiert angeboten und können dadurch deutlich flexibler konsumiert und ausgewertet werden. Die HystrixCommands unterstützen seit Version 1.5.3 nun außerdem die Cancellation, so dass dem ausführenden Thread ein interrupt-Signal gesendet wird, wenn auf dem Future ein cancel() aufgerufen wird oder ein unsubscribe() auf der Subscription.

Für Hystrix 2.0 ist das Update auf Java 8 geplant – das wird die Verwendung von Hystrix deutlich kompakter machen.

Fazit

Es wurde erläutert warum in verteilten Systemen immer mit dem Ausfall von Resourcen gerechnet werden muss und wie die Funktionen von Hystrix dabei helfen ein Resilient-Software-Design zu erreichen.  Dieser Artikel ist ein kurzer Einstieg in das Thema und ist der Auftakt einer mehrteiligen Blogartikel-Serie zum Thema Hystrix in der verschiedene codecentric-Kollegen ihr Praxiswissen zum Thema teilen werden. Im nächsten Teil wird unter anderem das Thema dynamische Konfiguration von Hystrix beleuchtet werden.

Felix Braun

Felix Braun ist Niederlassungsleiter FFM und Senior Agile IT Consultant bei codecentric. Seine Schwerpunkte sind Microservices, cloud-native Architekturen und agile Entwicklung. Als früherer Volleyball-Profi weiß er, wie wichtig gute Teamarbeit für ein erfolgreiches Projekt ist.

Share on FacebookGoogle+Share on LinkedInTweet about this on TwitterShare on RedditDigg thisShare on StumbleUpon

Kommentieren

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.