#JAVAPRO #Microservices #Spring
Mit Hilfe von Spring Initializr, einem Online-Generator zum Erzeugen von Service-Hüllen auf Basis des Micro-Frameworks Spring Boot, und den zahlreichen Spring-Guides ist ein erster eigener Microservice schnell erzeugt. Doch wie geht es weiter? Dieser Artikel beschreibt verschiedene Komponenten, mit deren Hilfe man Schritt für Schritt der Produktionsreife näher kommt.
Ein einzelner Service lässt sich leicht manuell konfigurieren: Typischerweise Datenbankverbindung, Verbindung zum Message-Broker, Security-Credentials etc. Doch was, wenn sich die Datenbankverbindung ändert und diese Information in vielen Services auf unterschiedlichen Umgebungen landen muss? Alle einzeln anzupassen und dann wieder zu deployen ist fehleranfällig und zeitintensiv.
Hilfe bietet hier das Projekt Spring Cloud Config. Es bietet server- und clientseitige Unterstützung, um die notwendige Service-Konfiguration zu externalisieren. Der Konfigurations-Server muss dabei nur wissen, wo er die Client-Parameter finden kann. Es existieren verschiedene Möglichkeiten, diese zu hinterlegen. Im Standard gibt man dem Server ein Git-Repository mit, welches sich auch lokal auf der Festplatte befinden kann. Vorteil dabei ist, dass alle Einstellungsmöglichkeiten der Clients von Anfang an zentral in einer Versionsverwaltung vorgehalten werden. Nun genügt es den Clients mitzuteilen, unter welcher Adresse sie den Config-Server erreichen. Per Default fragen die Services diesen nur beim Start an. Eine Abfrage in Intervallen nach etwaigen Konfigurationsänderungen ist aber ebenso möglich.
Eureka
Damit die Services sich gegenseitig finden, wird eine zentrale Registrierung benötigt, bei der die Instanzen sich anmelden. Heureka kommt aus dem Altgriechischen und heißt so viel wie „Ich habe es gefunden“. Die Service-Discovery Eureka wurde, wie etliche andere Module in diesem Umfeld, ursprünglich von Netflix entwickelt. Der Filme-Anbieter gilt mit seiner Streaming-Plattform als einer der Pioniere im Bereich der Microservices und hat zahlreiche seiner intern entwickelten Projekte inzwischen als Open-Source zur Verfügung gestellt. Ein Eureka-Server ist schnell aufgesetzt. Dem Client muss man nur noch mitteilen, wo er die Zentralinstanz findet. Registriert er sich bei Eureka, übermittelt er Informationen über die Adresse unter der erreichbar ist, seine Startseite sowie eine Health-URL. Im Standard nutzt Eureka einen Heartbeat des Clients, um zu entscheiden ob dieser aktiv ist. Default sind hier 30 Sekunden. Der Client kann aber leicht auch so konfiguriert werden, dass er über die Healthcheck-URL detaillierte Informationen zu seinem momentanen Status liefert. Aktuell liegt Eureka noch in der Version 1.0 vor. Für die kommende Version sind etliche Verbesserungen vorgesehen.
So erhält momentan noch jeder Client alle Informationen, die der Zentralinstanz vorliegen. Da im Normalfall nur eine Teilmenge benötigt wird, soll es dem Client künftig möglich sein, dem Server mitzuteilen welche Informationen er benötigt. So erhält er zum Beispiel nur die Adresse eines bestimmten Webservices.
Des Weiteren pullen aktuell die Clients Eureka, um sich über Updates zu informieren. In der neuen Version pusht der Server diese Informationen. Verbesserungen sind außerdem im Bereich der Replikation und der Auto-Skalierbarkeit vorgesehen. Und: Ist das aktuelle Dashboard noch eher rudimentär, soll dann auch die Einsicht in etliche Zusatzinformationen möglich sein. Beispielsweise können über ein Audit-Log alle Änderungen an der Registrierung eingesehen werden.
Hystrix
Circuit Breaker gehören zu den sogenannten Stabilitätsmustern, das dazu dient, wiederkehrende Verbindungsfehler zu einer Ressource aufzuspüren und den Zugriff darauf für eine bestimmte Zeit zu blockieren. Nachzulesen in dem sehr empfehlenswerten Buch „Release It!“. Hystrix ist eine Gattung der Stachelschweine – sowie der Name der Netflix-Bibliothek, die das Circuit-Breaker-Muster implementiert. Das Framework dient dazu, Services in verteilten Systemen vor Ausfällen externer Abhängigkeiten zu schützen bzw. solche Probleme besser zu kontrollieren und zu monitoren. Kaskadierende Fehler (wie bei einem Dominoeffekt führt der Ausfall eines Dienstes zum Ausfall weiterer Dienste) werden vermieden. Beantwortet ein externes System innerhalb eines konfigurierbaren Zeitfensters zu viele Anfragen nicht oder nur mit einem Fehlerstatus, so werden die Anfragen an dieses System langsam zurückgefahren. Nun können zum Bespiel aufgestaute Anfragen abgearbeitet werden und die Selbstheilungskräfte des Systems greifen. So ist auch das Bild des Circuit Breakers zu verstehen: [tooltip text=”vgl. Nygard, Michael T.: “Release It! : Design and Deploy Productionready Software”. 1. Aufl. 2007, ISBN: 978-0-978-73921-8″ trigger=”hover”]Bei Problemen im Netzwerk löst die Sicherung aus[/tooltip] und wird erst wieder geschlossen, wenn das verursachende Problem nicht mehr auftritt. Bei dem aufrufenden Service müssen natürlich entsprechende Fallback-Mechanismen implementiert sein, aber auch hier unterstützt die Bibliothek.
Hystrix kommt zusammen mit einem Dashboard, dem alle entscheidenden Hystrix-Metriken entnommen werden können. Im Standard kann so nur ein Service überwacht werden. Netflix Turbine bündelt die Informationsflüsse unterschiedlicher Service-Instanzen. So können auch ganze Service-Cluster in einem Dashboard verwaltet werden, wie in dem Beispielbild von der Projektseite gut zu erkennen ist.
Ribbonz
Skalierung macht erst dann wirklich Sinn, wenn auch ein intelligentes Load-Balancing genutzt wird. So können die Anfragen verteilt und unter Volllast stehende Server aus der Schusslinie genommen werden. Ribbon bietet clientseitiges Load-Balancing, um mit einem Service-Cluster zu kommunizieren. Dabei erhält jeder Client die Adressen der einzelnen Service-Instanzen. Diese können nach Bedarf auch in Zonen gruppiert werden. Der Client kann nun nach beliebigen Kriterien wie Round-Robin oder einer gewünschten Zone entscheiden, welche Instanz er anfragt. Dabei werden Statistiken zu dem Antwortverhalten erstellt, so dass der Client bei Folgeaufrufen Server mit problematischen Antwortzeiten ausklammern kann. Nutzt man Ribbon zusammen mit Eureka, so wird die Serverliste automatisch zur Verfügung gestellt. (vgl. Abb.1)
Feign
Feign stammt ebenfalls aus der Netflix-Schmiede und ist ein Webservice-Client, der das Erstellen von Anfragen an Webservices erleichtern soll. Da er sehr einfach mit Eureka und Ribbon zusammen verwendet kann, erhält man so einen HTTP-Client mit eigenem Load-Balancing. Wird zusätzlich Hystrix genutzt, ist es möglich, auch auf Service-Ausfälle adäquat zu reagieren.
Zuul
Clientseitiges Load-Balancing funktioniert für die Kommunikation interner Services – gewöhnlich verborgen hinter einer Firewall. Externe Clients dagegen bringen ihre eigenen, zusätzlichen Anforderungen an Sicherheit, Payload und Protokolle mit sich. Ein Edge-Server kann die Aufrufe dieser Clients an die Services bündeln und bearbeiten. Hier können API- und Protokoll-Übersetzungen vorgenommen und Sicherheitsaspekte behandelt
werden.
Zuul ist so ein Edge-Server, die Eingangstür von externen Aufrufen an das eigene Backend. Der Name des Frameworks ist dem gleichnamigen Torwächter-Dämon aus dem Film „Ghostbusters“ entliehen. Zuul ermöglicht dynamisches Routen der Anfragen, Monitoring und unterstützt in Punkto Sicherheit. Zusätzlich existiert ein Embedded-Reverse-Proxy auf Basis von Zuul. Dabei werden Anfragen eines UI-Clients zu einem oder mehreren Backend-Services durch den Proxy geleitet. Probleme mit Cross-Origin Resource Sharing (CORS) und der Same-Origin-Policy werden so umgangen.
Dank Ribbon erhält man Load-Balancing frei Haus dazu und Hystrix unterstützt in Sachen Fehler-Handling.
Sleuth und Zipkin
Solange man mit einem Monolithen arbeitet, ist die Analyse einer Anfrage relativ banal: Welches Problem auch immer auftreten mag, die Verantwortung liegt im Monolithen. Verteilte Systeme aber ändern alles. Sleuth ist der englische Ausdruck für Detektiv oder auch Schnüffler. Spring Cloud Sleuth unterstützt verteiltes Tracing und hilft, nicht nur das spezifizierte, sondern vor allem auch das reale Verhalten des Systems zu verstehen. Der Weg einer einzelnen Anfrage über mehrere Instanzen hinweg wird dabei als Trace bezeichnet, während der Sprung von einer Instanz zur Nächsten ein Span ist. Sleuth instrumentalisiert automatisch verschiedene Kommunikationswege in einem Spring-Cloud System:
• Anfragen über einen Message-Broker wie Kafka oder RabbitMQ
• HTTP-Header, die von Spring MVC Kontrollern empfangen werden
• Anfragen über den Zuul Proxy-Mechanismus
• Anfragen eines Rest-Templates
Sleuth erweitert die Log-Nachrichten jeweils mit einer Span- und einer Trace-ID. Mit einem geeigneten Analyse-Tool können die Log-Files auf diese IDs hin untersucht und ausgewertet werden. Um ein Ausufern der dabei gesammelten Daten zu vermeiden, kann konfiguriert werden, dass beispielsweise nur 10 Prozent der Anfragen so instrumentalisiert werden.
Doch das Sammeln der Daten ist nur eine Seite der Medaille. Die andere ist das Verstehen dieser Daten. Dazu kann Zipkin verwendet werden. Es basiert auf dem Konzept von Google Dapper und wurde ursprünglich bei Twitter entwickelt. Zipkin speichert die von Sleuth generierten Daten standardmäßig in einer MySQL-Datenbank oder hält die Informationen im Arbeitsspeicher vor. Das mitgelieferte Dashboard ermöglicht es, diese Daten dann zu analysieren und abzufragen. (vgl. Abb.2)
Was fehlt?
Noch bevor man die erste Zeile Code schreibt, sollte man sich über zwei Punkte Gedanken machen, die gerne erst im Nachhinein implementiert werden – was dann oft unnötig kompliziert und fehleranfällig ist. Zum einen ist dies das Thema Logging. Um schnell und einfach die Log-Meldungen potentiell sehr vieler
Instanzen auszuwerten, ist eine zentralisierte Lösung unabdingbar. Großer Beliebtheit erfreut sich hier zum Beispiel der sogenannte ELK-Stack. Er besteht aus der Suchlösung Elasticsearch, Logstash zum Einsammeln der Log-Files von den Servern und Kibana als grafischem Dashboard zur Analyse der in Elasticsearch
gespeicherten Log-Meldungen. Von vornherein berücksichtigt werden sollte auch das Thema Security, das oft sträflich vernachlässigt wird. Hier sei exemplarisch auf Spring Cloud Vault und Spring Cloud Security verwiesen.
Fazit
Als Architektur-Design sind Microservices immer noch recht neu. Micro-Frameworks wie Spring Boot, Grails, Play, Payara Micro, Dropwizard, WildFly Swarm oder Lagom buhlen um die Gunst der User. Jedes Framework bietet andere Vor- und Nachteile, will ausprobiert und verstanden werden. Es bleibt abzuwarten,
welche Lösungsansätze sich nachhaltig durchsetzen werden. Auch in der Spring-Cloud-Welt ist noch viel Bewegung. Daher nie vergessen: Alles ist im Fluss!
Max Wenzel arbeitet als freiberuflicher Softwareentwickler und -architekt. Er unterstützt seine Kunden in den Bereichen Microservices und Big Data. Sein neuestes Steckenpferd sind die Themen Machine Learning und Künstliche Intelligenz. Wenn er nicht gerade beim Kunden vor Ort ist, findet man ihn auf
Entwicklerkonferenzen oder einem Meetup – immer in dem Bemühen, sein Fachwissen auf aktuellem Stand zu halten und sich mit anderen Entwicklern auszutauschen.