Spring Boot für Microservices

Eine frühlingshafte Lösung für Microservices

Eberhard Wolff

Die Implementierung von Microservices stellt im Vergleich zu monolithischen Anwendungen Entwickler vor einige Herausforderungen. Spezialisierte Technologien wie Spring Boot unterstützen die Umsetzung von Microservices und machen so den Projekten das Leben leichter.

Microservices [1] sind ein möglicher Ansatz, um Anwendungen zu modularisieren. Das besondere: Die Module können unabhängig voneinander in Produktion gebracht werden. Während Module wie Java Packages oder Java Klassen alle gemeinsam in einem deploybaren Artefakt landen und dann auch gemeinsam in Produktion gebracht werden müssen, ist das bei Microservices anders. Konkret sind Microservices getrennte Prozesse, die als Docker Container oder eigene virtuelle Maschinen noch weiter gegeneinander isoliert werden können. Sie bieten REST-Services an oder können jeweils einen Teil einer Website implementieren.

Letztendlich wird so eine Anwendung in viele Prozesse aufgeteilt. Genau das führt zu einigen Herausforderungen. Während in einer monolithischen Anwendung nur ein Prozess mit einem Build-Projekt umgesetzt werden muss, ist bei Microservices die Anzahl der Projekte wesentlich größer. Also stellt sich eine Frage: Wie aufwändig ist es, ein neues Projekt zu erstellen? Bei Spring Boot ist dafür nicht besonders viel notwendig:

  • Es muss ein Build-Skript geben – geschrieben beispielsweise mit Maven oder Gradle oder auch mit Ant.
  • In dem Build-Skript sind nur wenige Einstellungen notwendig. Für Maven ist ein Plug-In notwendig und eine Abhängigkeit zu der Bibliothek spring-boot-starter-web, wenn eine Web-Anwendung implementiert werden soll. Es gibt zahlreiche weitere Spring Boot Starter für bestimmte Anwendungsarten wie beispielsweise Batches oder Integrations-Anwendungen. Diese Starter stellen dann eine vollständige Umgebung bereit, die alle Bibliotheken für eine Anwendung eines bestimmten Typs enthält – also beispielsweise eine Web-Anwendung wie in diesem Beispiel.
  • Es sollte eine Java-Klasse geben, die dann das System startet. Listing 1 zeigt ein Beispiel. Mit @RestControllerwird diese Klasse so markiert, dass sie RESTful-HTTP-Anfragen entgegennehmen kann. @RequestMapping sorgt dafür, dass die Methode auf die Root-URL der Anwendung reagiert. Der String hello wird als Body der HTTP Response zurückgegeben. Alle diese Annotation sind Standard-Spring-Annotation aus dem Spring Framework selber. @EnableAutoConfiguration ist eine Spring-Boot-Annotation. Sie sorgt dafür, dass eine für die Anwendung passende Umgebung geschaffen wird. Im Beispiel wird ein Servlet Container und eine Spring-Web-Umgebung gestartet, da es sich um eine Web-Anwendung handelt. Das geschieht durch den Code in der ´main´-Methode. Auch dieser Code nutzt Spring Boot spezifische Klassen.

    @RestController  
    @EnableAutoConfiguration  
    public class ControllerAndMain {

      @RequestMapping("/")  
      public String hello() {  
        return "hello";
      }

      public static void main(String[] args) {
        SpringApplication.run(ControllerAndMain.class, args);
      }

    }

Mit Spring Boot ist es also sehr einfach, einen neuen Microservice umzusetzen. Viel weiter lässt sich der Aufwand kaum reduzieren. Irgendein Build ist eigentlich für jede Java-Anwendung notwendig. Viel einfacher als eine Spring-Boot-Build kann er aber kaum werden. Ein Beispiel zeigt [2]. Spring Boot unterstützt auch Groovy. Dann ist kein Build notwendig und die benötigte Unterstützung ergibt sich aus den Annotationen der Groovy-Klasse.

Kommunikation: REST und Messaging

Microservices müssen irgendwie miteinander kommunizieren. Wie das Code-Beispiel i Listing 1 schon gezeigt hat, unterstützt das Spring-MVC-Framework REST. Außerdem bietet Spring Boot JAX RS an. Es gibt einen passenden Starter für die JAX-RS-Implementierung Jersey. Und auch Spring HATEOAS wird mit einem Starter unterstützt. Dieses Framework unterstützt vor allem Links und Hypermedia-Formate wie HAL, die für REST-Anwendungen sehr wichtig sind. Schließlich gibt es in Spring Cloud eine Unterstützung für Feign. Spring Cloud ist eine Sammlung von Erweiterungen für Spring Boot. Dazu zählt auch eine Unterstützung für den Netflix-Stack, der die Entwicklung von Microservices vereinfacht. Ein Teil dieses Stacks ist Feign. Das Framework nutzt ähnliche Ansätze für die Entwicklung von REST-Clients wie sie sonst bei der Implementierung von REST-Servern genutzt werden: Ein Interface wird mit JAX-RS-Annotationen oder Spring-Annotation wie @RequestMapping versehen. Wenn eine Methode des Interfaces aufgerufen wird, dann erfolgt ein Aufruf des REST-Servers. So werden die Aufrufe an das Interface hinter den Kulissen zu REST-Aufrufen. Durch die Annotationen ist die Lösung sehr flexibel und gleichzeitig ist die Nutzung des Interfaces für den Aufrufer sehr einfach.

Spring Boot bietet von sich aus also schon eine breite Auswahl von REST-Libraries. Sollte das nicht ausreichen, können beliebige andere Java-Bibliotheken in einer Spring-Boot-Anwendung verwendet werden. Schließlich ist ein Spring-Boot-Projekt auch nur eine Java-Projekt. Gegebenenfalls sind dabei einige Details zu beachten – beispielsweise müssen Servlets in einer Spring-Boot-Umgebung als Spring Beans konfiguriert werden. Ein Starter erleichtert nur die Integration beispielsweise durch eine passende Konfiguration und einer Unterstützung von Spring-Boot-Konfigurationsansätzen in der Anwendung. Zwangsläufig notwendig ist er jedoch nicht, um eine bestimmte Technologie nutzen zu können.

Neben REST ist Messaging eine andere Möglichkeit zur Kommunikation von Microservices [3]. Messaging kommt mit typischen Herausforderungen verteilter Systeme wie dem Ausfall einzelner Systeme oder der Netzwerkkommunikation recht gut zurecht. Daher können sie eine sehr sinnvolle Alternative sein.

Messaging auf der Java-Plattform kann mit dem Java Message Service (JMS) implementiert werden – ein Standard, der eine API für den Zugriff auf entsprechende Middleware definiert. Spring Boot bietet Starter für JMS-Implementierungen wie HornetQ oder Artemis. Doch damit nicht genug: Spring Boot unterstützt auch AMQP (Advanced Messaging Queuing Protocol). Dieser Standard definiert keine API, sondern ein Netzwerkprotokoll für den Versand von Nachrichten. Spring Boot hat einen Starter für RabbitMQ, eine der wichtigsten AMQP-Implementierungen. Und in Spring Cloud findet sich das Modul Spring Cloud Streams, das neben RabbitMQ auch Kafka und Redis unterstützt. Redis ist eigentlich als NoSQL-Datenbank bekannt, hat aber auch eine Messaging-Lösung. Kafka hat sich vor allem für die Implementierung von Systemen mit besonders hohen Performance-Anforderungen bewährt. Die Bibliothek Spring Cloud Modules ist ebenfalls nützlich für Messaging-Microservices. Es unterstützt Spring-Integration-Anwendungen. Dieses Framework setzt auch für die Implementierung der einzelnen Services auf Messaging, das dann in einer JVM läuft. Schließlich kann Spring Cloud Bus Nachrichten verschicken, wenn die Konfiguration einer Spring-Boot-Anwendung geändert werden muss – ebenfalls eine Messaging-Anwendung aus dem Spring-Boot-Bereich.

Sowohl für REST als auch für Messaging stellt Spring Boot also eine bereite Auswahl an unterstützen Frameworks zur Verfügung. Auch hier gilt: Sollte eine andere Bibliothek notwendig sein, kann auch diese in einer Spring-Boot-Anwendung genutzt werden.

Deployment

Da ein Microservice-System aus einer Vielzahl von Microservices besteht und jeder Produktion gebracht werden muss, ist es besonders wichtig, ein einfaches Deployment zu ermöglichen. Dazu zählt auch die Konfiguration der Anwendung. Das Deployment muss in einer Microservices-Umgebung automatisiert werden, so dass die Komplexität des Deployments scheinbar keine große Rolle spielt – schließlich ist sowieso alles automatisiert. Wenn aber die Technologie das Deployment schon vereinfacht, ist auch die Automatisierung recht einfach machbar. Außerdem ist es von Vorteil, wenn die Anwendungen einheitlich deployt werden können. Dann können nämlich alle Microservices mit einem größtenteils identischen Ansatz in Produktion gebracht werden.

Spring Boot bietet einen solchen Ansatz an. Mit dem schon zitierten Maven-Plug-In oder einem analogen Ansatz für die anderen Build Systeme erstellt Spring Boot ein JAR. Dieses JAR kann mit einem einfachen Kommandozeilenbefehl gestartet werden, wenn ein Java-Laufzeit auf dem Rechner installiert ist. Das JAR enthält alle notwendigen Bibliotheken und den Code, um die eigentliche Anwendung zu starten. Ein solches JAR ist bei einer minimalen Anwendung weniger als 14 MB groß. Ein Spring-Boot-JAR kann durch einen einfachen Link auch zu einem Linux Service werden, der dann beim Start des Servers automatisch mitgestartet werden kann und mit den entsprechenden Linux-Werkezeugen administriert werden kann.

Spring Boots eigene Infrastruktur wie auch der selbst geschriebene Code können mit einem einheitlichen Konfigurationsmechanismus konfiguriert werden. Dazu können Konfigurationsdatei im JAR und im Verzeichnisbaum des Servers aber auch Umgebungsvariablen oder Kommandozeilenparameter ausgewertet werden. Natürlich können die Konfigurationsdateien durch entsprechende Werkzeuge generiert werden.

Konfigurationsdateien sind zwar einfach, aber decken sicher nicht alle Anforderungen ab. Spring Cloud Config stellt einen Server bereit, der Konfigurationen an Spring-Boot-Anwendungen im Netz verteilen kann. Die Konfiguration kann verschlüsselt sein und mit git versioniert werden. Ebenso ist es möglich, Änderungen der Konfiguration zur Laufzeit an die Anwendungen zu verteilen. Durch Spring-Mechanismen können auch Teile der Anwendung neu gestartet werden, um so die Konfigurationsänderungen wirklich zu aktivieren. Durch Spring Cloud Config ist allerdings der Zustand einer Anwendung ohne die Kenntnis der Konfiguration im Konfigurationsserver nicht mehr klar. Das kann Fehlersuche und -analyse komplizierter machen. Dynamische Konfigurationsänderungen sind zwar interessant, aber genauso gut können Server mit einer aktualisierten Konfiguration gestartet werden und dann die Server mit der alten Konfiguration schrittweise ersetzten.

Neben einem JAR kann Spring Boot auch ein WAR erzeugen, das auf einem Application Server laufen kann. Das JAR-Deployment ist einfacher und hat keine Einschränkungen. Daher sollte man das JAR-Deployment vorziehen. Wenn allerdings der Betrieb auf WARs und Application Server ausgelegt ist, bietet Spring Boot durch das WAR-Deployment eine passende Unterstützung.

Monitoring

Wie beim Deployment gilt auch beim Monitoring: Microservices sind so zahlreich, dass ein einheitlicher und einfacher Ansatz sehr wichtig ist, weil sonst der Betrieb der Umgebung zu kompliziert wird. Spring Boot bietet dazu Spring Boot Actuator [4]. Diese Bibliothek exponiert Metriken beispielsweise aus den HTTP-Zugriffen wie Antwortzeit oder die Zahl der Zugriffe auf bestimmte URLs. Diese Metriken kann Spring Boot Actuator über das Carbon-Protokoll bereit, das Monitoring-Lösungen wie Graphite oder Grafana nutzen. Ebenso können die Informationen über eine RESTful-HTTP-JSON-Schnittstelle ausgelesen werden oder über JMX (Java Management Extension), den Standard für das Monitoring in der Java-Welt. Ebenso gibt es eine Integration für Dropwizard Metrics. Diese Bibliothek ist auf die Erfassung von Metriken spezialisiert und bietet selber zahlreiche Schnittstellen für den Export der Daten. Spring Boot selber kann außerdem die Daten in StatsD, Open TSDB oder Redis exportieren. Spring Boot erreicht damit eine breite Unterstützung verschiedener Monitoring-Technologien.

Health Checks

Health Checks sind mit Metriken verwandt, aber geben nur eine Auskunft darüber, ob ein Microservice gerade Anfragen bearbeiten kann oder nicht. Anhand eines Health Checks kann beispielsweise ein Load Balancer entscheiden, ob der Microservice Anfragen bearbeiten kann oder aus dem Load Balancing entfernt werden soll. Spring Boot Actuator bietet diese Information über ein HTTP URL als JSON an. Diese Information kann auch mit eigenem Code erweitert werden und auch den Zustand beispielsweise einer Datenbank in den Health Check einbeziehen. Solche Health Checks sind fundamental, um Load Balancing wirklich sinnvoll umzusetzen.

Sicherheit

Spring Boot hat einen Spring Boot Starter für das Spring Security Framework. Dieses Framework setzt einige typischen Sicherheitsmechanismen um. Es kann über verschiedene Protokolle wie HTTP BASIC eine Authentifizierung auslesen. Beispielsweise mit Hilfe von Annotation können die notwendigen Rechte und Rollen für die Autorisierung definiert werden. Ebenso kann eine Authentifizierung über OAuth2 erfolgen. Dabei findet die Authentifizierung beispielsweise mit Benutzername und Passwort gegen einen Server statt, der dann ein Token zurückgibt. Dieses Token kann dann zur Authentifizierung bei den Microservices genutzt werden. So muss ein Benutzer nur einmal seinen Benutzernamen und Passwort eingeben. Dennoch kann jeder Microservice anhand der Informationen im Token entscheiden, welche Funktionalitäten der jeweilige Benutzer verwenden darf. So sind alle Fachlichkeiten einschließlich der Autorisierung im Microservice implementiert. Ein solcher Ansatz ist für Microservice-Architekturen sehr wichtig, um alle Logik zu einer Domäne tatsächlich in einem Microservice unterzubringen – und dazu gehört auch die Logik, wer auf welche Daten zugreifen darf.

Resilience

Bei Resilience geht es darum, dass ein Microservice beim Ausfall anderer Microservices immer noch weiter funktioniert. Resilience bedeutet so viel wie Widerstandsfähigkeit. Der Ausfall eines Microservices kann durch einen Cache, Vorgabewerte oder eine Einschränkung des Service kompensiert werden. In Spring Boot bietet Spring Cloud eine Integration von Hystrix, einer Bibliothek aus dem Netflix Stack. Sie hilft bei der Implementierung dieser Ansätze. Hystrix hat noch verschiedene andere Features:

  • Timeouts brechen den Aufruf anderer Microservices nach einiger Zeit ab. Dadurch wird vermieden, dass der eigene Microservice zu lange auf andere Microservices wartet und schließlich auch blockiert ist.
  • Durch Circuit Breaker (Sicherungen) wird der Aufruf anderer Systeme unterbunden, wenn das System gerade ausgefallen ist. Dadurch sind dann keine Timeouts notwendig, um das Blockieren des Microservice zu vermeiden. Nach einiger Zeit schließt sich der Circuit Breaker wieder, so dass Request wieder an den Microservice gehen. Wenn der Microservice dann wieder zuverlässig arbeitet, gehen auch alle Folgerequests an den Microservice. Da sich die Circuit Breaker nach und nach schließen, wird der Microservice erst nach und nach wieder seine volle Last erreichen. Das macht es wahrscheinlicher, dass der Microservice nach einem Neustart auch wieder funktioniert.
  • Schließlich bietet das Hystrix Dashboard ein eigenes Monitoring, das durch den Zustand der Hystrix Circuit Breaker und Thread Pools einen guten Eindruck vom aktuellen Zustand des Systems gibt.

Hystrix gehört eigentlich nicht zu Spring Boot oder Spring Cloud, aber die Integration erfolgt mit Annotationen und entspricht weitestgehend dem, wie auch andere Technologien in Spring integriert sind. Das erleichtert die Nutzung dieser Technologien.

Fazit

Spring Boot besticht vor allem mit dem Umfang der Lösung. Durch die Integration des Spring Stacks und vieler anderer Technologien, gibt es kaum ein Problem, für das Spring Boot nicht eine Lösung vorhält. Spring Boot kann weit mehr als nur Microservices: Da Spring Boot alle Features bietet, die sonst auch in Spring-Anwendungen nutzbar sind, und gleichzeitig eine erhebliche Vereinfachung darstellt, sollte eigentlich jedes Spring-Projekt diese Technologie nutzen.

Neben der Unterstützung für REST, Messaging und Fat-JAR-Deployment sind es vor allem die Metriken und Health Checks, die bei Spring Boot besonders geeignet für Microservices machen. Schließlich bestehen Microservice-Systeme aus einer Vielzahl von System, die auch alle in ein Monitoring integriert werden müssen. Eine einheitliche Technologie erleichtert das erheblich. Ebenso sind die Bereiche Sicherheit und Resilience sinnvoll abgedeckt.

Mit Spring Boot schafft es das Spring Framework auch nach über einem Jahrzehnt aktuell und relevant zu bleiben – selbst in einem relativ neuen Bereich wie Microservices. Für die Einarbeitung lohnt sich ein Blick auf die Spring Boot Guides [5].

Feature Spring Boot
Minimale Anwendung Eine Java-Klassen + ein Build Skript (z.B. Maven, Gradle)
REST Unterstützung Ja
REST APIs Direkte Unterstützung mit Spring Boot Starter für Spring MVC, JAX- RS (Jersey), Spring HATEOAS, Feign in Spring Cloud. Weitere Bibliotheken auch ohne direkte Unterstützung nutzbar.
Messaging Unterstützung Ja
Messaging APIs JMS (HornetQ, Artemis), AMQP (RabbitMQ), Spring Cloud Streams (Rabbit, Redis, Kafka), Spring Cloud Modules (für Spring- Integration-Anwendungen), Spring Cloud Bus zur Kommunikation von Konfigurationsänderungen.
Fat JAR Deployment Ja
Build Tools Maven, Gradle, Ant
Konfiguration Für Infrastruktur und eigene Anwendung mit Hilfe von Dateien im JAR oder Dateisystem des Servers, Kommandozeilenparameter oder Umgebungsvariablen. Spring Cloud Config als zentraler Konfigurationsserver mit dynamischen Updates.
Metriken Ja
Protokolle HTTP JSON REST, JMX, Redis, StatsD, Open TSDB, zahlreiche weitere über Dropwizard Metrics
Sicherheit Unterstützung praktisch aller gängigen Authentifizierungs- und Autorisierungsansätze mit Hilfe von Spring Security. Insbesondere auch OAuth2 was für dezentrale Security in Microservice- Architekturen sehr sinnvoll ist
Health Check Ja
Protokolle / Daten HTTP JSON REST. Der Health Check kann auch erweitert werden und weitere technische Komponenten wie beispielsweise Datenbanken in den Check einbeziehen
Stärken Sehr umfangreiche Lösung auf Basis des etablierten und weit verbreiteten Spring-Stacks. Umfangreiche Dokumentation
Resilience Durch die Hystrix-Integration in Spring Cloud
Tabelle 1: Überblick über die Spring-Boot-Features

Links & Literatur

  1. Eberhard Wolff: Microservices: Grundlagen flexibler Software Architekturen, dpunkt, 2015, ISBN 978–3864903137  ↩

  2. https://github.com/ewolff/spring-boot-demos/tree/master/simplest-spring-boot  ↩

  3. https://jaxenter.de/microservices-rest-vs-messaging-29875  ↩

  4. http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#production-ready  ↩

  5. https://spring.io/guides/  ↩

Thumb ewolff

Eberhard Wolff arbeitet als Fellow bei der innoQ Deutschland GmbH und berät in dieser Funktion Kunden in Bezug auf Architekturen und Technologien. Außerdem ist er Java Champion. Sein technologischer Schwerpunkt liegt auf modernen Architektur-Ansätzen - Cloud, Continuous Delivery, DevOps, Microservices oder NoSQL spielen oft eine Rolle. Er ist Autor von über hundert Artikeln und Büchern. Sein neuestes Buch handelt von Microservices und ist auch auf Englisch erschienen

Weitere Inhalte

Java magazin
Dieser Artikel ist ursprünglich in Ausgabe 06/2016 der Zeitschrift JavaMagazin erschienen. Die Veröffentlichung auf innoq.com erfolgt mit freundlicher Genehmigung des S&S Media-Verlags.

Kommentare

Um die Kommentare zu sehen, bitte unserer Cookie Vereinbarung zustimmen. Mehr lesen