image

image

Eberhard Wolff arbeitet seit mehr als fünfzehn Jahren als Architekt und Berater – oft an der Schnittstelle zwischen Business und Technologie. Er ist Fellow bei der innoQ. Als Autor hat er über hundert Artikel und Bücher geschrieben – u.a. über Continuous Delivery – und als Sprecher auf internationalen Konferenzen vorgetragen. Sein technologischer Schwerpunkt liegt auf modernen Architekturansätzen – Cloud, Continuous Delivery, DevOps, Microservices oder NoSQL spielen oft eine Rolle.

Sie können dieses E-Book ebenfalls und kostenlos in der englischen Version hier herunterladen.

image

Zu diesem Buch – sowie zu vielen weiteren dpunkt.büchern – können Sie auch das entsprechende E-Book im PDF-Format herunterladen. Werden Sie dazu einfach Mitglied bei dpunkt.plus+:

www.dpunkt.plus

Eberhard Wolff

Das Microservices-Praxisbuch

Grundlagen, Konzepte und Rezepte

image

Eberhard Wolff
eberhard.wolff@gmail.com

Lektorat: René Schönfeldt

Bibliografische Information der Deutschen Nationalbibliothek

ISBN:

1. Auflage 2018

Die vorliegende Publikation ist urheberrechtlich geschützt. Alle Rechte vorbehalten. Die Verwendung der Texte und Abbildungen, auch auszugsweise, ist ohne die schriftliche Zustimmung des Verlags urheberrechtswidrig und daher strafbar. Dies gilt insbesondere für die Vervielfältigung, Übersetzung oder die Verwendung in elektronischen Systemen.

5 4 3 2 1

Inhaltsübersicht

Einleitung

Teil IArchitekturgrundlagen

1Microservices

2Mikro- und Makro-Architektur

3Self-contained System (SCS)

4Migration

Teil IITechnologie-Stacks

5Docker-Einführung

6Technische Mikro-Architektur

7Konzept: Frontend-Integration

8Rezept: Links und clientseitige Integration

9Rezept: serverseitige Integration mit Edge Side Includes (ESI)

10Konzept: Asynchrone Microservices

11Rezept: Messaging und Kafka

12Rezept: Asynchrone Kommunikation mit Atom und REST

13Konzept: Synchrone Microservices

14Rezept: REST mit dem Netflix-Stack

15Rezept: REST mit Consul und Apache httpd

16Konzept: Microservices-Plattformen

17Rezept: Docker-Container mit Kubernetes

18Rezept: PaaS mit Cloud Foundry

Teil IIIBetrieb

19Konzept: Betrieb

20Rezept: Monitoring mit Prometheus

21Rezept: Log-Analyse mit dem Elastic Stack

22Rezept: Tracing mit Zipkin

23Und nun?

Anhang

AInstallation der Umgebung

BMaven-Kommandos

CDocker- und Docker-Compose-Kommandos

Index

Inhaltsverzeichnis

Einleitung

Teil IArchitekturgrundlagen

1Microservices

1.1Microservices: Definition

1.2Gründe für Microservices

1.3Herausforderungen

1.4Independent-Systems-Architecture-Prinzipien (ISA)

1.5Bedingungen

1.6Prinzipien

1.7Bewertung

1.8Variationen

1.9Fazit

2Mikro- und Makro-Architektur

2.1Bounded Context und Strategic Design

2.2Technische Mikro- und Makro-Architektur

2.3Betrieb: Mikro- oder Makro-Architektur

2.4Mikro-Architektur bevorzugen!

2.5Organisatorische Aspekte

2.6Variationen

2.7Fazit

3Self-contained System (SCS)

3.1Gründe für den Begriff Self-contained Systems

3.2Self-contained Systems: Definition

3.3Ein Beispiel

3.4SCS und Microservices

3.5Herausforderungen

3.6Variationen

3.7Fazit

4Migration

4.1Gründe für eine Migration

4.2Typische Migrationsstrategie

4.3Alternative Strategien

4.4Build, Betrieb und Organisation

4.5Variationen

4.6Fazit

Teil IITechnologie-Stacks

5Docker-Einführung

5.1Docker für Microservices: Gründe

5.2Docker-Grundlagen

5.3Docker-Installation und Docker-Kommandos

5.4Docker-Hosts mit Docker Machine installieren

5.5Dockerfiles

5.6Docker Compose

5.7Variationen

5.8Fazit

6Technische Mikro-Architektur

6.1Anforderungen

6.2Reactive

6.3Spring Boot

6.4Go

6.5Variationen

6.6Fazit

7Konzept: Frontend-Integration

7.1Frontend: Monolith oder modular?

7.2Optionen

7.3Resource-oriented Client Architecture (ROCA)

7.4Herausforderungen

7.5Vorteile

7.6Variationen

7.7Fazit

8Rezept: Links und clientseitige Integration

8.1Überblick

8.2Beispiel

8.3Rezept-Variationen

8.4Experimente

8.5Fazit

9Rezept: serverseitige Integration mit Edge Side Includes (ESI)

9.1ESI: Konzepte

9.2Beispiel

9.3Varnish

9.4Rezept-Variationen

9.5Experimente

9.6Fazit

10Konzept: Asynchrone Microservices

10.1Definition

10.2Events

10.3Herausforderungen

10.4Vorteile

10.5Variationen

10.6Fazit

11Rezept: Messaging und Kafka

11.1Message-oriented Middleware (MOM)

11.2Die Architektur von Kafka

11.3Events mit Kafka

11.4Beispiel

11.5Rezept-Variationen

11.6Experimente

11.7Fazit

12Rezept: Asynchrone Kommunikation mit Atom und REST

12.1Das Atom-Format

12.2Beispiel

12.3Rezept-Variationen

12.4Experimente

12.5Fazit

13Konzept: Synchrone Microservices

13.1Definition

13.2Herausforderungen

13.3Vorteile

13.4Variationen

13.5Fazit

14Rezept: REST mit dem Netflix-Stack

14.1Beispiel

14.2Eureka: Service Discovery

14.3Router: Zuul

14.4Lastverteilung: Ribbon

14.5Resilience: Hystrix

14.6Rezept-Variationen

14.7Experimente

14.8Fazit

15Rezept: REST mit Consul und Apache httpd

15.1Beispiel

15.2Service Discovery: Consul

15.3Routing: Apache httpd

15.4Consul Template

15.5Consul und Spring Boot

15.6DNS und Registrator

15.7Rezept-Variationen

15.8Experimente

15.9Fazit

16Konzept: Microservices-Plattformen

16.1Definition

16.2Variationen

16.3Fazit

17Rezept: Docker-Container mit Kubernetes

17.1Kubernetes

17.2Das Beispiel mit Kubernetes

17.3Beispiel im Detail

17.4Weitere Kubernetes-Features

17.5Rezept-Variationen

17.6Experimente

17.7Fazit

18Rezept: PaaS mit Cloud Foundry

18.1PaaS: Definition

18.2Cloud Foundry

18.3Das Beispiel mit Cloud Foundry

18.4Rezept-Variationen

18.5Experimente

18.6Serverless

18.7Fazit

Teil IIIBetrieb

19Konzept: Betrieb

19.1Warum Betrieb wichtig ist

19.2Ansätze für den Betrieb von Microservices

19.3Auswirkungen der behandelten Technologien

19.4Fazit

20Rezept: Monitoring mit Prometheus

20.1Grundlagen

20.2Metriken bei Microservices

20.3Metriken mit Prometheus

20.4Beispiel mit Prometheus

20.5Rezept-Variationen

20.6Experimente

20.7Fazit

21Rezept: Log-Analyse mit dem Elastic Stack

21.1Grundlagen

21.2Logging mit dem Elastic Stack

21.3Beispiel

21.4Rezept-Variationen

21.5Experimente

21.6Fazit

22Rezept: Tracing mit Zipkin

22.1Grundlagen

22.2Tracing mit Zipkin

22.3Beispiel

22.4Rezept-Variationen

22.5Fazit

23Und nun?

Anhang

AInstallation der Umgebung

BMaven-Kommandos

CDocker- und Docker-Compose-Kommandos

Index

Einleitung

Microservices sind einer der wichtigsten Software-Architektur-Trends, grundlegende Werke über Microservices gibt es schon. Unter anderem auch das Microservices-Buch (http://microservices-buch.de)1 vom Autor dieses Werks. Warum noch ein weiteres Buch über Microservices?

Es ist eine Sache, eine Architektur zu definieren. Sie umzusetzen, ist eine ganz andere Sache. Dieses Buch stellt technologische Ansätze für die Umsetzung von Microservices vor und zeigt die jeweiligen Vor- und Nachteile.

Dabei geht es um Technologien für ein Microservices-System als Ganzes. Jeder Microservice kann anders implementiert werden. Daher sind die technologischen Entscheidungen für die Frameworks innerhalb der Microservices nicht so wichtig wie die Entscheidungen für das gesamte System. Die Entscheidung für ein Framework kann in jedem Microservice revidiert werden. Technologien für das Gesamtsystem sind kaum änderbar.

Grundlagen

Um Microservices zu verstehen, ist eine Einführung in die Architektur, ihre Vor- und Nachteile und Spielweisen unerlässlich. Die Grundlagen sind in dem Buch soweit erläutert, wie sie für das Verständnis der praktischen Umsetzungen notwendig sind.

Konzepte

Microservices benötigen Lösungen für verschiedene Herausforderungen. Dazu zählen Konzepte zur Integration (Frontend-Integration, synchrone und asynchrone Microservices) und zum Betrieb (Monitoring, Log-Analyse, Tracing). Microservices-Plattformen wie PaaS oder Kubernetes stellen vollständige Lösungen für den Betrieb von Microservices dar.

Rezepte

Das Buch nutzt Rezepte als Metapher für die Technologien, mit denen die Konzepte umgesetzt werden können. Jeder Ansatz hat viel mit einem Rezept gemeinsam:

Für jedes Rezept gibt es ein ablauffähiges Beispiel mit der konkreten Technologie. Die Beispiele sind einzeln ablauffähig und bauen nicht aufeinander auf. So kann der Leser sich mit den für ihn interessantesten Rezepten und Beispielen beschäftigen, ohne sich dabei mit anderen Beispielen befassen zu müssen.

So liefert das Buch einen Einstieg, um einen Überblick über die Technologien zu bekommen und einen Technologie-Stack auszuwählen. Danach kann der Leser sich anhand der im Buch enthaltenen Links weiter in die relevanten Technologien vertiefen.

Aufbau des Buchs

Dieses Buch besteht aus drei Teilen.

Teil I – Architektur-Grundlagen

Teil I gibt eine Einführung in die Architektur-Grundlagen, die mit Kapitel 1 beginnt.

image

Abb. 1Überblick über Teil I

Teil II – Technologie-Stacks

Technologie-Stacks stehen im Mittelpunkt von Teil II, der mit Kapitel 5 beginnt.

image

Abb. 2Überblick über Teil II

Teil III – Betrieb

Den Betrieb einer Vielzahl von Microservices sicherzustellen, ist eine große Herausforderung. Teil III (ab Kapitel 19) diskutiert mögliche Rezepte zur Lösung.

image

Abb. 3Überblick über Teil III

Abschluss und Anhänge

Abschließend bietet das Kapitel 23 noch einen Ausblick.

Die Anhänge erklären die Installation der Software (Anhang A), die Benutzung des Build-Werkzeugs Maven (Anhang B) sowie Docker und Docker Compose (Anhang C), mit denen die Umgebungen für die Beispiele betrieben werden.

Zielgruppe

Das Buch erläutert Grundlagen und technische Aspekte von Microservices. Es ist für verschiedene Zielgruppen interessant:

Vorwissen

Das Buch setzt grundlegendes Wissen über Software-Architektur und Software-Entwicklung voraus. Die praktischen Beispiele sind so dokumentiert, dass sie mit wenig Vorwissen ausgeführt werden können. Das Buch fokussiert auf Technologien, die für Microservices in verschiedenen Programmiersprachen genutzt werden können. Die Beispiele sind in Java mit den Frameworks Spring Boot und Spring Cloud geschrieben, sodass für Änderungen an dem Code Java-Kentnisse notwendig sind.

Quick Start

Das Buch vermittelt vor allem Technologien. Zu jeder Technologie in jedem Kapitel gibt es ein Beispiel. Um schnell praktische Erfahrungen mit den Technologien zu sammeln und anhand der Beispiele nachzuvollziehen, gibt es einen Quick Start:

Sowohl für den Build mit Maven als auch für Docker und Docker Compose enthalten die Kapitel Anleitungen zum Troubeshooting.

Die Beispiele sind in folgenden Abschnitten erläutert:

Konzept

Rezept

Abschnitt

Frontend-Integration

Links & clientseitige Integration

8.2

Frontend-Integration

Edge Side Includes (ESI)

9.2

Asynchrone Microservices

Kafka

11.4

Asynchrone Microservices

REST & Atom

12.2

Synchrone Microservices

Netflix-Stack

14.1

Synchrone Microservices

Consul & Apache httpd

15.1

Microservices-Plattform

Kubernetes

17.3

Microservices-Plattform

Cloud Foundry

18.3

Betrieb

Monitoring mit Prometheus

20.4

Betrieb

Log-Analyse mit Elastic Stack

21.3

Betrieb

Tracing mit Zipkin

22.2

Die Projekte sind alle auf GitHub verfügbar. In den Projekten gibt es jeweils eine Datei WIE-LAUFEN.md mit einer Schritt-für-Schritt-Anleitung, wie die Demos installiert und gestartet werden können.

Die Beispiele bauen nicht aufeinander auf. Dadurch ist es möglich, mit einem beliebigen Beispiel loszulegen.

Danksagung

Ich möchte allen danken, mit denen ich über Microservices diskutiert habe, die mir Fragen gestellt oder mit mir zusammengearbeitet haben. Es sind viel zu viele, um sie alle zu nennen. Der Dialog hilft sehr und macht Spaß!

Viele der Ideen und auch die Umsetzungen sind ohne meine Kollegen bei der innoQ nicht denkbar. Insbesondere möchte ich Alexander Heusingfeld, Christian Stettler, Christine Koppelt, Daniel Westheide, Gerald Preissler, Jörg Müller, Lucas Dohmen, Marc Giersch, Michael Simons, Michael Vitz, Philipp Neugebauer, Simon Kölsch, Sophie Kuna und Stefan Lauer danken.

Weiteres wichtiges Feedback kam von Merten Driemeyer und Olcay Tümce.

Schließlich habe ich meinen Freunden, Eltern und Verwandten zu danken, die ich für das Buch oft vernachlässigt habe – insbesondere meiner Frau.

Und natürlich gilt mein Dank all jenen, die an den in diesem Buch erwähnten Technologien gearbeitet und so die Grundlagen für Microservices gelegt haben.

Bei den Entwicklern der Werkzeuge von https://www.softcover.io/ möchte ich mich ebenfalls bedanken.

Last but not least möchte ich dem dpunkt.verlag und René Schönfeldt danken, der mich sehr professionell bei der Erstellung des Buchs unterstützt hat.

Website

Die Website zum Buch ist http://microservices-praxisbuch.de/. Dort finden sich die Errata und Links zu den Beispielen.

Teil I

Architekturgrundlagen

Der erste Teil des Buchs stellt die grundlegenden Ideen der Microservices-Architektur vor.

Microservices

Das Kapitel 1 klärt die Grundlagen von Microservices: Was sind Microservices? Welche Vor- und Nachteile hat diese Architektur?

Self-contained Systems

Das Kapitel 3 beschreibt Self-contained Systems. Sie sind eine Sammlung von Best Practices für Microservices-Architekturen, bei der eine starke Unabhängigkeit und Web-Anwendungen im Mittelpunkt stehen. Neben Vor- und Nachteilen geht es um mögliche Variationen dieser Idee.

Mikro- und Makro-Architektur

Microservices bieten viele Freiheiten. Dennoch müssen einige Entscheidungen übergreifend über alle Microservices eines Systems getroffen werden. Das Kapitel 2 stellt das Konzept der Mikro- und Makro-Architektur vor. Die Mikro-Architektur umfasst alle Entscheidungen, die für jeden Microservice anders getroffen werden können. Die Makro-Architektur sind die Entscheidungen, die für alle Microservices gelten. Neben den Bestandteilen einer Mikro- und Makro-Architektur stellt das Kapitel auch vor, wer eine Makro-Architektur entwirft.

Migration

Die meisten Microservices-Projekte migrieren ein vorhandenes System in eine Microservices-Architektur. Daher stellt das Kapitel 4 mögliche Ziele einer Migration und verschiedene Migrationsstrategien vor.

1Microservices

Dieses Kapitel bietet eine Einführung in das Thema »Microservices«. Das Studium dieses Kapitels vermittelt dem Leser:

1.1Microservices: Definition

Leider gibt es für den Begriff »Microservice« keine allgemein anerkannte Definition. Im Rahmen dieses Buchs gilt folgende Definition:

Microservices sind unabhängig deploybare Module.

Beispielsweise kann ein E-Commerce-System in Module für den Bestellprozess, die Registrierung oder die Produktsuche aufgeteilt werden. Normalerweise wären alle diese Module gemeinsam in einer Anwendung implementiert. Dann kann eine Änderung in einem der Module nur in Produktion gebracht werden, indem eine neue Version der Anwendung und damit aller Module in Produktion gebracht wird. Wenn die Module aber als Microservices umgesetzt sind, kann der Bestellprozess nicht nur unabhängig von den anderen Modulen geändert werden, sondern er kann sogar unabhängig in Produktion gebracht werden.

Das beschleunigt das Deployment und verringert die Anzahl der notwendigen Tests, da nur ein Modul deployt wird. Im Extremfall wird durch die größere Entkopplung ein großes Projekt zu einer Menge kleinerer Projekte, die jeweils einen der Microservices verantworten.

Technisch ist es dazu notwendig, dass der Microservice ein eigener Prozess ist. Besser wäre eine eigene virtuelle Maschine oder ein Docker-Container, die Microservices noch stärker entkoppeln. Ein Deployment ersetzt dann den Docker-Container durch einen neuen Docker-Container, fährt die neue Version hoch und lässt dann die Request auf die Version umschwenken. Die anderen Microservices bleiben davon unbeeinflusst.

1.1.1Vorteile der Microservices-Definition

Diese Definition von Microservices als unabhängig deploybare Module hat mehrere Vorteile:

1.1.2Deployment-Monolith

Ein System, das nicht aus Microservices besteht, kann nur als Ganzes deployt werden. Es ist ein Deployment-Monolith. Natürlich kann der Deployment-Monolith in Module aufgeteilt sein. Über den internen Aufbau sagt dieser Begriff nichts aus.

1.1.3Größe eines Microservice

Die Definition von Microservices trifft keine Aussage über die Größe eines Microservice. Der Name »Microservice« legt den Verdacht nahe, dass es um besonders kleine Services geht. Aber in der Praxis findet man sehr unterschiedliche Größen von Microservices. Einige Microservices beschäftigen ein ganzes Team, während andere nur hundert Zeilen lang sind. Die Größe eignet sich also tatsächlich nicht als Teil der Definition.

1.2Gründe für Microservices

Für die Nutzung von Microservices gibt es eine Vielzahl von Gründen.

1.2.1Microservices zum Skalieren der Entwicklung

Ein Grund für den Einsatz von Microservices ist die Skalierung der Entwicklung. Große Teams sollen gemeinsam an einem komplexen Projekt arbeiten. Mithilfe von Microservices können die Teams weitgehend unabhängig arbeiten:

Durch Microservices können die Teams somit fachlich und technisch unabhängig arbeiten. Das erlaubt es, auch große Projekte ohne großen Koordinierungsaufwand zu stemmen.

1.2.2Legacy-Systeme ablösen

Die Wartung und Erweiterung eines Legacy-Systems ist eine Herausforderung, weil der Code meistens schlecht strukturiert ist und Änderungen oft nicht durch Tests abgesichert sind. Dazu kann noch eine veraltete technologische Basis kommen.

Microservices helfen bei der Arbeit mit Legacy-Systemen, weil der Code nicht unbedingt geändert werden muss. Stattdessen können neben das alte System neue Microservices gestellt werden. Dazu ist eine Integration zwischen dem alten System und den Microservices notwendig – beispielsweise per Datenreplikation, per REST, Messaging oder auf der UI-Ebene. Außerdem müssen Probleme wie ein einheitliches Single Sign On über das alte System und die neuen Microservices gelöst werden.

Dafür sind die Microservices dann praktisch ein Greenfield: Es gibt keine vorhandene Codebasis, auf die aufgesetzt werden muss. Ebenso kann ein komplett anderer Technologiestack genutzt werden. Das erleichtert die Arbeit gegenüber einer Modifikation des Legacy-Systems erheblich.

1.2.3Nachhaltige Entwicklung

Microservices versprechen, dass Systeme auch langfristig wartbar bleiben.

Ein wichtiger Grund dafür ist die Ersetzbarkeit der Microservices. Wenn ein einzelner Microservice nicht mehr wartbar ist, kann er neu geschrieben werden. Das ist im Vergleich zu einem Deployment-Monolithen mit weniger Aufwand verbunden, weil die Microservices kleiner sind als ein Deployment-Monolith.

Allerdings ist es schwierig, einen Microservice zu ersetzen, von dem viele andere Microservices abhängen, weil Änderungen die anderen Microservices beeinflussen können. Also müssen für die Ersetzbarkeit auch die Abhängigkeiten zwischen den Microservices gemanagt werden.

Die Ersetzbarkeit ist eine wesentliche Stärke von Microservices. Viele Entwickler arbeiten daran, Legacy-Systeme zu ersetzen. Aber beim Entwurf eines neues Systems wird viel zu selten die Frage gestellt, wie das System abgelöst werden kann, wenn es zu einem Legacy-System geworden ist. Die Ersetzbarkeit von Microservices ist eine mögliche Antwort.

Für die Wartbarkeit müssen die Abhängigkeiten zwischen den Microservices langfristig gemanagt werden. Auf dieser Ebene haben klassische Architekturen oft Schwierigkeiten: Ein Entwickler schreibt Code und führt dabei unabsichtlich eine neue Abhängigkeit zwischen zwei Modulen ein, die eigentlich in der Architektur verboten war. Das merkt der Entwickler üblicherweise noch nicht einmal, weil er nicht die Architektur-Ebene, sondern nur die Code-Ebene des Systems im Blick hat. Aus welchem Modul die Klasse stammt, zu der er gerade eine Abhängigkeit einführt, ist oft nicht sofort zu erkennen. So entstehen mit der Zeit immer mehr Abhängigkeiten. Gegen die ursprüngliche Architektur mit den geplanten Abhängigkeiten wird immer mehr verstoßen und am Ende steht ein völlig unstrukturiertes System.

Microservices haben klare Grenzen durch ihre Schnittstelle – egal ob die Schnittstelle als REST-Schnittstelle oder durch Messaging implementiert ist. Wenn ein Entwickler eine neue Abhängigkeit zu einer solchen Schnittstelle einführt, merkt er das, weil die Schnittstelle entsprechend bedient werden muss. Aus diesem Grund ist es unwahrscheinlich, dass auf der Ebene der Abhängigkeiten zwischen den Microservices Architektur-Verstöße geschehen. Die Schnittstellen der Microservices sind sozusagen Architektur-Firewalls, weil sie ArchitekturVerstöße aufhalten. Das Konzept einer Architektur-Firewall setzen auch Architektur-Managementwerkzeuge wie Sonargraph (https://www.hello2morrow.com/products/sonargraph), Structure101 (http://structure101.com/) oder jQAssistant (https://jqassistant.org/) um. Fortgeschrittene Modul-Konzepte können ebenfalls solche Firewalls erzeugen. In der Java-Welt beschränkt OSGi (https://www.osgi.org/) andere Module auf den Zugriff über die Schnittstelle. Der Zugriff kann sogar auf einzelne Packages oder Klassen eingeschränkt werden.

Also bleiben einzelne Microservices wartbar, weil sie ersetzt werden können, wenn sie nicht mehr wartbar sind. Die Architektur auf Ebene der Abhängigkeiten zwischen den Microservices bleibt ebenfalls wartbar, weil Entwickler Abhängigkeiten zwischen Microservices nicht mehr unbeabsichtigt einbauen können.

Daher können Microservices langfristig eine hohe Qualität der Architektur sicherstellen und damit eine nachhaltige Entwicklung, bei der die Änderungsgeschwindigkeit auch langfristig nicht abnimmt.

1.2.4Continuous Delivery

Continuous Delivery1 ist ein Ansatz, bei dem Software kontinuierlich in Produktion gebracht wird. Dazu wird eine Continuous-Delivery-Pipeline genutzt. Die Pipeline bringt die Software durch die verschiedenen Phasen in Produktion (siehe Abbildung 1–1).

image

Abb. 1–1Continuous-Delivery-Pipeline

Typischerweise wird die Software in der Commit-Phase kompiliert, die Unit Tests und eine statische Code-Analyse werden durchgeführt. In der Akzeptanztestphase überprüfen automatisierte Tests die fachlich korrekte Funktion der Software. Die Kapazitätstests überprüfen die Performance für die zu erwartende Last. Explorative Tests dienen dazu, bisher noch nicht bedachte Tests durchzuführen oder neue Funktionalitäten zu testen. Die explorativen Tests können so Aspekte untersuchen, die automatisierte Tests noch nicht abdecken. Am Ende wird die Software in Produktion gebracht.

Microservices stellen unabhängig deploybare Module dar. Also hat jeder Microservice eine eigene Continuous-Delivery-Pipeline. Das erleichtert Continuous Delivery:

Microservices helfen also bei Continuous Delivery. Die bessere Unterstützung von Continuous Delivery alleine kann schon ein Grund für eine Migration eines Deployment-Monolithen zu Microservices sein.

Microservices-Architekturen können aber nur dann funktionieren, wenn das Deployment automatisiert ist. Microservices erhöhen die Anzahl der deploybaren Einheiten gegenüber einem Deployment-Monolithen erheblich. Das ist nur machbar, wenn die Deployment-Prozesse automatisiert werden.

Tatsächlich unabhängiges Deployment bedeutet, dass die Continuous-Delivery-Pipelines vollständig unabhängig sind. Integrationstests widersprechen dieser Unabhängigkeit: Sie führen Abhängigkeiten zwischen den Continuous-Delivery-Pipelines verschiedener Microservices ein. Also müssen die Integrationstests auf ein Minimum reduziert werden. Abhängig von der Kommunikationsart gibt es dafür unterschiedliche Ansätze (siehe Abschnitt 13.1 und Abschnitt 10.3).

1.2.5Robustheit

Microservices-Systeme sind robuster. Wenn in einem Microservice ein Speicherleck existiert, stürzt nur dieser Microservice ab. Die anderen Microservices laufen weiter. Natürlich müssen die anderen Microservices den Ausfall eines Microservice kompensieren. Man spricht von Resilience (etwa Widerstandsfähigkeit). Microservices können dazu beispielsweise Werte cachen und diese Werte bei einem Ausfall nutzen. Oder es gibt einen Fallback mit einem vereinfachten Algorithmus.

Ohne Resilience kann die Verfügbarkeit eines Microservices-Systems problematisch sein. Dass irgendein Microservice ausfällt, ist recht wahrscheinlich. Durch die Aufteilung in mehrere Prozesse sind viel mehr Server an dem System beteiligt. Jeder dieser Server kann ausfallen. Die Kommunikation zwischen den Microservices verläuft über das Netzwerk. Das Netzwerk kann ebenfalls ausfallen. Also müssen die Microservices Resilience umsetzten, um Robustheit zu erreichen.

Der Abschnitt 14.5 zeigt, wie Resilience in einem synchronen Microservice-System konkret umgesetzt werden kann.

1.2.6Unabhängige Skalierung

Jeder Microservice kann unabhängig skaliert werden: Es ist möglich, mehr Instanzen eines Microservices zu starten und die Last für den Microservice auf die Instanzen zu verteilen. Das kann die Skalierbarkeit eines Systems erheblich verbessern. Dazu müssen die Microservices natürlich entsprechende Voraussetzungen schaffen. So dürfen die Microservices keinen State enthalten. Sonst können Clients nicht auf eine andere Instanz umschwenken, die ja den State dann nicht hätte.

Mehr Instanzen eines Deployment-Monolithen zu starten, kann aufgrund der benötigten Hardware schwierig sein. Außerdem kann der Aufbau einer Umgebung für einen Deployment-Monolithen komplex sein: So können zusätzliche Dienste notwendig sein oder eine komplexe Infrastruktur mit Datenbanken und weiteren Software-Komponenten. Bei einem Microservice kann die Skalierung feingranularer erfolgen, sodass üblicherweise weniger zusätzliche Dienste notwendig sind und Rahmenbedingungen weniger komplex sind.

1.2.7Technologiewahlfreiheit

Jeder Microservice kann mit einer eigenen Technologie umgesetzt werden. Das erleichtert die Migration auf eine neue Technologie, da man jeden Microservice einzeln migrieren kann. Ebenso ist es einfacher und risikoärmer, Erfahrungen mit neuen Technologien zu sammeln. Sie können zunächst nur für einen Microservice genutzt werden, bevor sie in mehreren Microservices zum Einsatz kommen.

1.2.8Sicherheit

Microservices können untereinander isoliert werden. So ist es möglich, zwischen den Microservices Firewalls in die Kommunikation einzuführen. Außerdem kann die Kommunikation zwischen den Microservices abgesichert werden, um zu garantieren, dass die Kommunikation tatsächlich von einem anderen Microservice kommt und authentisch ist. So kann verhindert werden, dass bei einer Übernahme eines Microservices auch andere Microservices kompromittiert sind.

1.2.9Allgemein: Isolation

Letztendlich lassen sich viele Vorteile der Microservices auf eine stärkere Isolation zurückführen.

image

Abb. 1–2Isolation als Quelle der Vorteile

Microservices können isoliert deployt werden, was Continuous Delivery vereinfacht. Sie sind bezüglich Ausfällen isoliert, was der Robustheit zugute kommt. Gleiches gilt für Skalierbarkeit: Jeder Microservice kann isoliert von anderen Microservices skaliert werden. Die eingesetzten Technologien können isoliert für einen Microservice bestimmt werden, was Technologiewahlfreiheit ermöglicht. Die Microservices sind so isoliert, dass sie nur über das Netzwerk miteinander kommunizieren. Die Kommunikation kann daher durch Firewalls abgesichert werden, was der Sicherheit zugute kommt.

Weil dank der starken Isolation die Modulgrenzen kaum noch aus Versehen überschritten werden können, wird die Architektur kaum noch verletzt. Das sichert die Architektur im Großen ab. Jeder Microservice kann isoliert durch einen neuen ersetzt werden. So kann risikoarm ein Microservice abgelöst werden und die Architektur der einzelnen Microservices sauber gehalten werden. Dadurch ermöglicht die Isolation eine langfristige Wartbarkeit der Software.

Mit der Isolation treiben Microservices die Entkopplung als wichtige Eigenschaft von Modulen auf die Spitze: Während Module normalerweise nur bezüglich Änderungen am Code und bezüglich der Architektur voneinander entkoppelt sind, geht die Entkopplung der Microservices darüber weit hinaus.

1.2.10Vorteile priorisieren

Welcher Grund für Microservices der wichtigste ist, hängt vom jeweiligen Szenario ab. Der Einsatz von Microservices in einem Greenfield-System ist eher die Ausnahme als die Regel. Oft gilt es, einen Deployment-Monolithen durch ein Microservices-System zu ersetzen (siehe auch Kapitel 4). Dabei spielen unterschiedliche Vorteile eine Rolle:

Die Skalierung der Entwicklung ist nicht das einzige Szenario für eine Migration. Wenn ein einziges Scrum-Team ein System mit Microservices umsetzen will, kann die Skalierung der Entwicklung kein sinnvoller Grund sein, weil die Entwicklungsorganisation dazu nicht ausreichend groß ist. Dennoch kann es andere Gründe geben: Continuous Delivery, technische Gründe wie Robustheit, unabhängige Skalierung, Technologiewahlfreiheit oder nachhaltige Entwicklung können in einem solchen Szenario eine Rolle spielen.

1.2.11Microservices sind ein Trade-Off

Abhängig von den Zielen kann ein Team bei der Umsetzung von Microservices Kompromisse eingehen. Wenn Robustheit ein Ziel der Microservices-Einführung ist, müssen die Microservices als getrennte Docker-Container umgesetzt werden. Jeder Docker-Container kann unabhängig abstürzen. Ist Robustheit kein Ziel, kommen Alternativen in Frage. Beispielsweise können mehrere Microservices als Java-Web-Anwendungen gemeinsam auf einem Java-Application-Server laufen. Sie laufen dann alle in einem Prozess und sind bezüglich der Robustheit nicht isoliert. Ein Speicherleck in einem Microservice bringt alle Microservices zum Absturz. Aber dafür ist die Lösung einfacher zu betreiben und kann der bessere Trade-Off sein.

1.2.12Zwei Ebenen von Microservices: fachlich und technisch

Die technischen und organisatorischen Vorteile weisen auf zwei Ebenen hin, in denen ein System in Microservices unterteilt werden kann:

image

Abb. 1–3Zwei Ebenen von Microservices

Abbildung 1–3 zeigt ein Beispiel für zwei Ebenen: Eine ECommerce-Anwendung ist fachlich in die Microservices Suche, Check Out, Inkasso und Lieferung aufgeteilt. Die Suche ist weiter aufgeteilt: Die Volltext-Suche ist von der Suche in Kategorien getrennt. Ein Grund dafür kann die getrennte Skalierung sein: Mit dieser Architektur kann die Volltext-Suche getrennt von der Suche in Kategorien skaliert werden, was ein Vorteil ist, wenn sie unterschiedlich hohe Last handhaben müssen. Ein weiterer Grund können unterschiedliche Technologien sein: Die Volltext-Suche kann mit einer Volltext-Suchmaschine umgesetzt sein, die für die Suche in Kategorien ungeeignet ist.

1.2.13Typische Anzahl von Microservices in einem System

Es ist schwer, eine typische Anzahl von Microservices in einem System anzugeben. Wenn man der Aufteilung aus diesem Kapitel folgt, dann sollten sich 10–20 grobgranulare Fachlichkeiten ergeben und für jede von ihnen ein bis drei Microservices. Es gibt allerdings auch Systeme mit weitaus mehr Microservices.

1.3Herausforderungen

Microservices haben nicht nur Vorteile, sondern halten auch Herausforderungen bereit:

1.3.1Vorteile und Nachteile abwägen