Suche
Spring Boot für Microservices

Eine frühlingshafte Lösung für Microservices: Spring Boot

Eberhard Wolff

 

Microservices sind in aller Munde. Auch auf der JAX beherrscht das Thema die Diskussionen um zeitgemäße Software-Architekturen, wie man am Session-Track „Microservices & Architecture“ ablesen kann. Eine Technologie für die Umsetzung von Microservices stellt Eberhardt Wolff in folgendem Artikel vor: Spring Boot.

573d7e08c96b430f0ed1dc4cversion12sizefull

Eberhardt Wolff

Eine frühlingshafte Lösung für Microservices

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 Entwicklern das Leben leichter.

Microservices im Videotutoriallogo-entwickler tutorials

Im entwickler.tutorial Microservices mit Spring Boot und Spring Cloud bereitet Sie Eberhard Wolff auf den Umgang mit Microservices vor. Wolff erklärt, was Microservices eigentlich sind und mit welchen Chancen und Herausforderungen die Arbeit mit ihnen verbunden ist. Es folgen detaillierte Erklärungen zum Umgang mit Docker und dem Spring Framework, ein Microservices-Beispiel aus der Praxis rundet das Tutorial ab.

Jetzt anmelden und das 3-in-1 Gratisturorial sichern!

 

Spring Boot für Microservices

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 aufwendig 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, Gradle oder auch mit Ant.
  • In dem Build-Skript sind nur wenige Einstellungen notwendig. Für Maven ist ein Plug-in und eine Abhängigkeit zu der Bibliothek spring-boot-starter-web notwendig, wenn eine Webanwendung implementiert werden soll. Es gibt zahlreiche weitere Spring Boot Starter für bestimmte Anwendungsarten wie Batches oder Integrationsanwendungen. Diese Starter stellen dann eine vollständige Umgebung bereit, die alle Bibliotheken für eine Anwendung eines bestimmten Typs enthält – also beispielsweise eine Webanwendung.
  • Es sollte eine Java-Klasse geben, die dann das System startet. Listing 1 zeigt ein Beispiel. Mit @RestController wird diese Klasse so markiert, dass sie RESTful-HTTP-Anfragen entgegennehmen kann. @RequestMapping sorgt dafür, dass die Methode auf den 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 selbst. @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-Webumgebung gestartet, da es sich um eine Webanwendung 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 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 ein 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 Codebeispiel in Listing 1 schon zeigt, 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 Hypermediaformate wie HAL, die für REST-Anwendungen 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 Interface aufgerufen wird, 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 flexibel, und gleichzeitig ist die Nutzung des Interfaces für den Aufrufer 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 ein 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.

Lesen Sie auch: Microservices 101: Varianten, Herausforderungen, Erfahrungen aus der Praxis

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 kann es eine sinnvolle Alternative sein.

Messaging auf der Java-Plattform lässt sich mit dem Java Message Service (JMS) implementieren – ein Standard, der ein 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 Message Queuing Protocol). Dieser Standard definiert kein 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 Stream, 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 Performanceanforderungen 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 breite Auswahl an unterstützen Frameworks zur Verfügung. Auch hier gilt: Sollte eine andere Bibliothek notwendig sein, kann auch sie in einer Spring-Boot-Anwendung genutzt werden.

Deployment: einheitlich ist besser

Da ein Microservices-System aus vielen Microservices besteht, die auch alle in Produktion gebracht werden müssen, 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, sodass 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 erwähnten 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 eine 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 kleinen 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 und mit den entsprechenden Linux-Werkezeugen administriert werden kann.

Spring Boots eigene Infrastruktur und auch der selbst geschriebene Code lassen sich mit einem einheitlichen Konfigurationsmechanismus konfigurieren. Dazu können Konfigurationsdateien 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.

Lesen Sie auch: Java EE meets Microservices – Liebe auf den zweiten Blick

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 lässt sich verschlüsseln und mit Git versionieren. 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 ersetzen.

Neben einem JAR kann Spring Boot auch ein WAR erzeugen, das auf einem Application Server laufen kann. Das JAR-Deployment ist aber 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: breite Unterstützung verschiedener Tools

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 bereitstellen, 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 Extensions), den Standard für das Monitoring in der Java-Welt. Ebenso gibt es eine Integration für Dropwizard/Metrics. Diese Bibliothek ist auf das Erfassen von Metriken spezialisiert und bietet selbst zahlreiche Schnittstellen für den Export der Daten. Spring Boot selbst 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: ohne geht es nicht

Health Checks sind mit Metriken verwandt, aber geben nur 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 einen HTTP-URL als JSON an. Diese Information lässt sich mit eigenem Code erweitern und auch den Zustand beispielsweise einer Datenbank in den Health Check einbeziehen. Solche Health Checks sind fundamental, um Load Balancing wirklich sinnvoll umzusetzen.

Sicherheit: zentrale Authentifizierung

Spring Boot hat einen Spring Boot Starter für das Spring-Security-Framework. Dieses Framework setzt einige typische Sicherheitsmechanismen um. So kann es über verschiedene Protokolle wie HTTP Basic eine Authentifizierung auslesen. Beispielsweise können die notwendigen Rechte und Rollen für die Autorisierung mithilfe von Annotationen definiert werden. Ebenso kann eine Authentifizierung über OAuth2 erfolgen. Dabei findet die Authentifizierung beispielsweise mit Benutzernamen und Passwort gegen einen Server statt, der dann ein Token zurückgibt. Dieses Token lässt sich dann zur Authentifizierung bei den Microservices nutzen. 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 Microservices-Architekturen 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 mit Hystrix

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 lässt sich durch einen Cache, Vorgabewerte oder eine Einschränkung des Service kompensieren. 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.

Time-outs 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 Time-outs notwendig, um das Blockieren des Microservice zu vermeiden. Nach einiger Zeit schließt sich der Circuit Breaker wieder, sodass Requests wieder an den Microservice gehen. Wenn der Microservice dann wieder zuverlässig arbeitet, gehen auch alle Folge-Requests 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 Threadpools 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.

Feature Spring Boot
Minimale Anwendung Eine Java-Klasse und 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 mithilfe 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 mithilfe von Spring Security. Insbesondere auch OAuth2, was für dezentrale Security in Microservices-Architekturen sinnvoll ist
Health Check Ja
Protokolle/Daten HTTP JSON REST. Der Health Check kann auch erweitert werden und weitere technische Komponenten wie Datenbanken in den Check einbeziehen
Stärken Sehr umfangreiche Lösung auf Basis des etablierten und weit verbreiteten Spring-StacksUmfangreiche Dokumentation
Resilience Durch die Hystrix-Integration in Spring Cloud

Tabelle 1: Überblick über die Spring-Boot-Features

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 klassischer Spring-Anwendungen bietet und gleichzeitig die Entwicklung stark vereinfacht, sollte eigentlich jedes Spring-Projekt diese Technologie nutzen.

Lesen Sie auch: Resilient Microservices – ein Architekturmuster für die Praxis

Neben der Unterstützung für REST, Messaging und Fat JAR Deployment sind es vor allem die Metriken und Health Checks, die Spring Boot besonders geeignet für Microservices machen. Schließlich bestehen Microservices-Systeme aus vielen 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].

Geschrieben von
Eberhard Wolff
Eberhard Wolff
Eberhard Wolff ist Fellow bei innoQ und arbeitet seit mehr als fünfzehn Jahren als Architekt und Berater, oft an der Schnittstelle zwischen Business und Technologie. Er ist Autor zahlreicher Artikel und Bücher, u.a. zu Continuous Delivery und Microservices und trägt regelmäßig als Sprecher auf internationalen Konferenz vor. Sein technologischer Schwerpunkt sind moderne Architektur- und Entwicklungsansätze wie Cloud, Continuous Delivery, DevOps, Microservices und NoSQL.
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.