Das Microservices-Praxisbuch - Eberhard Wolff - E-Book

Das Microservices-Praxisbuch E-Book

Eberhard Wolff

0,0

Beschreibung

Microservices haben viele Vorteile: Effizient mehr Features umsetzen, Software schneller in Produktion bringen, Robustheit und einfache Skalierbarkeit zählen dazu. Aber die Implementierung einer Microservices-Architektur und die Auswahl der notwendigen Technologien sind schwierige Herausforderungen. Dieses Buch zeigt Microservices-Rezepte, die Architekten anpassen und zu einem Microservices-Menü kombinieren können. So kann die Implementierung der Microservices individuell auf die Anforderungen im Projekt angepasst werden. Eberhard Wolff führt zunächst in Microservices, Self-contained Systems, Mikro- und Makro-Architektur und die Migration hin zu Microservices ein. Der zweite Teil zeigt die Microservices-Rezepte: Basis-Technologien wie Docker oder PaaS, Frontend-Integration mit Links, JavaScript oder ESI (Edge Side Includes). Es schließen sich asynchrone Microservices mit Apache Kafka oder REST Atom an. Bei den synchronen Ansätzen bespricht das Buch REST mit dem Netflix-Stack, Consul und Kubernetes. Zu jedem Rezept gibt es Hinweise zu Variations- und Kombinationsmöglichkeiten. Der Ausblick greift den Betrieb von Microservices auf und zeigt außerdem, wie der Leser ganz konkret mit Microservices beginnen kann. Das Buch bietet das technische Rüstzeug, um eine Microservices-Architektur umzusetzen. Demo-Projekte und Anregungen für die Vertiefung im Selbststudium runden das Buch ab.

Sie lesen das E-Book in den Legimi-Apps auf:

Android
iOS
von Legimi
zertifizierten E-Readern
Kindle™-E-Readern
(für ausgewählte Pakete)

Seitenzahl: 403

Das E-Book (TTS) können Sie hören im Abo „Legimi Premium” in Legimi-Apps auf:

Android
iOS
Bewertungen
0,0
0
0
0
0
0
Mehr Informationen
Mehr Informationen
Legimi prüft nicht, ob Rezensionen von Nutzern stammen, die den betreffenden Titel tatsächlich gekauft oder gelesen/gehört haben. Wir entfernen aber gefälschte Rezensionen.



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.

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

Eberhard [email protected]

Lektorat: René Schönfeldt

Projektmanagement: Miriam Metsch

Copy-Editing: Petra Kienle, Fürstenfeldbruck

Satz: III-satz, www.drei-satz.de

Herstellung: Susanne Bröckelmann

Umschlaggestaltung: Helmut Kraus, www.exclam.de

Druck und Bindung: M.P. Media-Print Informationstechnologie GmbH, 33100 Paderborn

Bibliografische Information der Deutschen Nationalbibliothek

Die Deutsche Nationalbibliothek verzeichnet diese Publikation in der Deutschen Nationalbibliografie; detaillierte bibliografische Daten sind im Internet über http://dnb.d-nb.de abrufbar.

ISBN:

Buch   978-3-86490-526-1

PDF     978-3-96088-461-3

ePub   978-3-96088-462-0

mobi   978-3-96088-463-7

1. Auflage 2018

Copyright © 2018 dpunkt.verlag GmbH

Wieblinger Weg 17

69123 Heidelberg

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.

Es wird darauf hingewiesen, dass die im Buch verwendeten Soft- und Hardware-Bezeichnungen sowie Markennamen und Produktbezeichnungen der jeweiligen Firmen im Allgemeinen warenzeichen-, marken- oder patentrechtlichem Schutz unterliegen.

Alle Angaben und Programme in diesem Buch wurden mit größter Sorgfalt kontrolliert. Weder Autor noch Verlag können jedoch für Schäden haftbar gemacht werden, die in Zusammenhang mit der Verwendung dieses Buches stehen.

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:

Jedes Rezept ist

praktisch

beschrieben, einschließlich einer technischen Implementierung als Beispiel. Bei den Beispielen liegt der Fokus auf

Einfachheit

. Jedes Beispiel kann leicht nachvollzogen, erweitert und modifiziert werden.

Das Buch bietet dem Leser eine

Vielzahl von Rezepten

. Der Leser muss aus diesen Rezepten für sein Projekt

eine Auswahl

treffen, so wie ein Koch es für sein Menü tut. Das Buch zeigt verschiedene Optionen. In der Praxis muss fast jedes Projekt anders angegangen werden. Dazu bieten die Rezepte die Basis.

Zu jedem Rezept gibt es

Rezept-Variationen

. Schließlich kann ein Rezept auf viele verschiedene Arten und Weisen umgesetzt werden. Das gilt auch für die Technologien in diesem Buch. Manchmal sind die Variationen so einfach, dass sie direkt als

Experiment

in dem ablauffähigen Beispiel umgesetzt werden können.

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.

Kapitel 1

klärt den Begriff »Microservice« und

Kapitel 3

erläutert Self-contained Systems als besonders praktikablen Ansatz für Microservices.

In einem Microservices-System gibt es die Ebenen der Mikro- und Makro-Architektur, die globale und lokale Entscheidungen darstellen (

Kapitel 2

).

Oft sollen alte Systeme in Microservices migriert werden (

Kapitel 4

).

Abb. 1Überblick über Teil I

Teil II – Technologie-Stacks

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

Docker

ist die Basis vieler Microservices-Architekturen (

Kapitel 5

). Es erleichtert das Ausrollen von Software und den Betrieb der Services.

Die

technische Mikro-Architektur

(

Kapitel 6

) beschreibt Technologien, die zur Implementierung eines Microservice genutzt werden können.

Eine Möglichkeit zur Integration ist das Konzept zur

Integration am WebFrontend

(

Kapitel 7

). Die Frontend-Integration führt zu einer losen Kopplung der Microservices und einer hohen Flexibilität.

Das Rezept aus

Kapitel 8

setzt für die Web-Frontend-Integration auf

Links

und auf

JavaScript

für das dynamische Nachladen von Inhalten. Dieser Ansatz ist einfach realisierbar und nutzt gängige Web-Technologien.

Auf dem Server kann die Integration mit

ESI (Edge Side Includes)

erfolgen (

Kapitel 9

). ESI ist in Caches implementiert, sodass das System eine höhere Performance und Zuverlässigkeit erreichen kann.

Das Konzept der

asynchronen Kommunikation

steht im Mittelpunkt von

Kapitel 10

. Asynchrone Kommunikation verbessert die Zuverlässigkeit und entkoppelt das Systems.

Eine asynchrone Technologie ist

Apache Kafka

(

Kapitel 11

), mit der Messages verschickt werden können. Kafka speichert die Nachrichten dauerhaft ab und erlaubt so die Rekonstruktion des Zustands eines Microservices aus den Nachrichten.

Die Alternative für asynchrone Kommunikation ist

Atom

(

Kapitel 12

), ein HTTP- und REST-basiertes Protokoll. Atom nutzt eine REST-Infrastruktur und kann daher sehr einfach umgesetzt werden.

Kapitel 13

stellt vor, wie das Konzept

synchroner Microservices

umgesetzt werden kann. Die synchrone Kommunikation zwischen Microservices wird in der Praxis sehr häufig genutzt, obwohl dieser Ansatz bei Antwortzeiten und Zuverlässigkeit Herausforderungen bereithalten kann.

Der

Netflix-Stack

(

Kapitel 14

) bietet Eureka für Service Discovery, Ribbon für Load Balancing, Hystrix für Resilience und Zuul für Routing. Netflix wird vor allem in der Java Community breit genutzt.

Consul

(

Kapitel 15

) ist eine Alternative für Service Discovery. Consul hat sehr viele Features und kann mit einer breiten Palette an Technologien genutzt werden.

Kapitel 16

erläutert das Konzept der

Microservices-Plattformen

, die den Betrieb und die Kommunikation der Microservices unterstützen.

Kubernetes

(

Kapitel 17

) ist eine Microservices-Plattform, die Docker Container ausführen kann, aber auch Service Discovery und Load Balancing löst. Der Microservice bleibt von dieser Infrastruktur unabhängig.

PaaS (Platform as a Service)

ist eine weitere Microservices-Plattform (

Kapitel 18

), die am Beispiel Cloud Foundry erläutert wird. Cloud Foundry ist sehr flexibel und kann auch im eigenen Rechenzentrum betrieben werden.

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.

Das

Kapitel 19

erläutert

Grundlagen

, und warum der Betrieb von Microservices so schwierig ist.

Im

Kapitel 20

geht es um

Monitoring

und das Werkzeug Prometheus. Prometheus unterstützt multidimensionale Datenstrukturen und kann die Monitoring-Werte auch von vielen Microservice-Instanzen analysieren.

Die

Analyse von Log-Daten

steht im Mittelpunkt von

Kapitel 21

. Als Werkzeug zeigt das Kapitel den Elastic Stack. Dieser Stack ist sehr weit verbreitet und stellt eine gute Basis für die Analyse auch großer Log-Datenmengen dar.

Tracing

verfolgt Aufrufe zwischen Microservices (

Kapitel 22

). Dazu kommt Zipkin zum Einsatz. Zipkin unterstützt verschiedene Plattformen und stellt einen De-facto-Standard für Tracing dar.

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:

Entwicklern

bietet

Teil II

eine Hilfe bei der Auswahl eines geeigneten Technologie-Stacks. Die Beispielprojekte dienen als Basis für das Einarbeiten in die Technologien. Die Microservices in den Beispielprojekten sind in Java mit dem Spring-Framework geschrieben, aber die Technologien in den Beispielen dienen zur Integration von Microservices, sodass weitere Microservices in anderen Sprachen ergänzt werden können.

Teil III

rundet das Buch in Richtung Betrieb ab, der für Entwickler immer wichtiger wird, und

Teil I

erläutert die grundlegenden Architektur-Konzepte.

Architekten

vermittelt

Teil I

das grundlegende Wissen über Microservices.

Teil II

und

Teil III

zeigen praktische Rezepte und Technologien, um die Architekturen umzusetzen. Damit geht das Buch weiter als ein reines Microservices-Architektur-Buch.

Für Experten aus den Bereichen

DevOps

und

Betrieb

stellen die Rezepte in

Teil III

eine Basis für eine Technologie-Bewertung von Betriebsaspekten wie Log-Analyse, Monitoring und Tracing von Microservices dar.

Teil II

zeigt Technologien für Deployment wie Docker, Kubernetes oder Cloud Foundry.

Teil I

beschreibt als Hintergrund die Konzepte hinter dem Microservices-Architektur-Ansatz.

Manager

bekommen in

Teil I

einen Überblick über die Vorteile des Architektur-Ansatzes und die besonderen Herausforderungen. Sie können bei Interesse an technischen Details

Teil II

und

Teil III

lesen.

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:

Zunächst muss auf dem Rechner die notwendige Software

installiert

sein. Die Installation beschreibt

Anhang A

.

Der Build der Beispiele erfolgt mit

Maven

. Den Umgang mit Maven erläutert

Anhang B

.

Die Beispiele setzen alle auf

Docker

und

Docker Compose

auf. Das

Anhang C

beschreibt die wichtigsten Befehle für Docker und Docker Compose.

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:

Vorteile (

Abschnitt 1.2

) und Nachteile (

Abschnitt 1.3

) von Microservices, um die Einsetzbarkeit dieses Architektur-Ansatzes in einem konkreten Projekt abschätzen zu können.

Die Vorteile zeigen auf, welche Probleme Microservices lösen und wie der Architekturansatz für bestimmte Szenarien angepasst werden kann.

Die Nachteile verdeutlichen, wo technische Risiken auftauchen können und wie man mit ihnen umgehen kann.

Schließlich haben Vor- und Nachteile Einfluss auf Technologie- und Architektur-Entscheidungen, die Vorteile verstärken und Nachteile vermindern sollen.

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:

Sie ist sehr

kompakt

.

Sie ist sehr

allgemein

und umfasst praktisch alle Arten von Systemen, die üblicherweise als Microservices bezeichnet werden.

Die Definition beruft sich auf

Module

und damit auf ein altes, gut verstandenes Konzept. So können viele Ideen zur Modularisierung übernommen werden. Außerdem wird so deutlich, dass Microservices Teile eines größeren Systems sind und niemals für sich stehen können. Deswegen müssen Microservices zwangsläufig mit anderen Microservices integriert werden.

Das unabhängige Deployment ist eine Eigenschaft, die zu vielen Vorteilen führt (siehe

Abschnitt 1.2

) und daher sehr wichtig ist. So zeigt die Definition trotz der Kürze, was die

wesentliche Eigenschaft

eines Microservices tatsächlich ist.

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:

Die meisten technischen Entscheidungen können die Teams allein treffen. Wenn die Microservices als Docker-Container ausgeliefert werden, muss jeder Docker-Container nur eine Schnittstelle für andere Container anbieten. Der interne Aufbau des Containers ist egal, solange die Schnittstelle vorhanden ist und korrekt funktioniert. Deswegen ist es beispielsweise egal, in welcher Programmiersprache der Microservice geschrieben wurde. Also kann das Team diese Entscheidung allein treffen. Natürlich kann die Wahl der Programmiersprache eingeschränkt werden, um Wildwuchs und zu große Komplexität zu vermeiden. Aber auch wenn die Wahl der Programmiersprache in einem Projekt eingeschränkt worden ist: Ein Bug Fix für eine Library kann ein Team immer noch unabhängig von den anderen Teams in einen Microservice einbauen.

Wenn ein neues Feature nur Änderungen an einem Microservice benötigt, kann es nicht nur unabhängig entwickelt werden, sondern es kann auch unabhängig in Produktion gebracht werden. So können die Teams vollständig unabhängig an Features arbeiten und sind fachlich unabhängig.

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).

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:

Der Durchlauf durch die Continuous-Delivery-Pipelines ist wesentlich

schneller

, weil die Deployment-Einheiten kleiner sind. Daher ist das Deployment schneller und so können Tests schneller Umgebungen aufbauen. Auch die Tests sind schneller, da sie weniger Funktionalitäten testen müssen. Nur die Features im jeweiligen Microservice müssen getestet werden, während bei einem Deployment-Monolithen wegen möglicher Regressionen die gesamte Funktionalität getestet werden muss.

Der Aufbau der Continuous-Delivery-Pipeline ist

einfacher

. Der Aufbau einer Umgebung für einen Deployment-Monolithen ist kompliziert. Meistens werden leistungsfähige Server benötigt. Ebenso sind oft Drittsysteme für Tests notwendig. Ein Microservice braucht weniger leistungsfähige Hardware. Es sind auch nicht so viele Drittsysteme in den Testumgebungen notwendig. Es kann allerdings notwendig sein, die Microservices zusammen in einem Integrationstest zu testen. Das kann diesen Vorteil zunichte machen.

Das Deployment eines Microservice hat ein

geringeres Risiko

als das Deployment eines Deployment-Monolithen. Bei einem Deployment Monolithen wird das komplette System neu deployt, bei einem Microservice nur ein Modul. Dabei sind weniger Probleme zu erwarten, weil weniger Funktionalität geändert wird.

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.

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 einfachere

Skalierung der Entwicklung

kann ein wichtiger Grund für die Einführung von Microservices in einem solchen Szenario sein. Oft haben große Organisationen Schwierigkeiten, einen Deployment-Monolithen mit einer Vielzahl von Entwicklern schnell genug weiterzuentwickeln.

Die

einfache Migration

weg von dem Legacy-Deployment-Monolithen erleichtert die Einführung von Microservices in einem solchen Szenario.

Continuous Delivery

ist oft ein weiteres Ziel: Die Geschwindigkeit, mit der Änderungen in Produktion gebracht werden können, soll erhöht werden. Oft ist auch die Zuverlässigkeit, mit der eine Änderung in Produktion gebracht werden kann, nicht ausreichend.

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:

Eine

grobgranulare fachliche Unterteilung

gewährt den Teams eine unabhängige Entwicklung und ermöglicht es, dass ein neues Feature mit einem Deployment eines Microservices ausgerollt wird. Beispielsweise können in einem ECommerce-System die Registrierung der Kunden oder der Bestellprozess solche grobgranularen Microservices sein.

Aus

technischen Gründen

können dann einige Microservices

weiter unterteilt

werden. Wenn beispielsweise der letzte Schritt des Bestellprozesses unter besonders hoher Last steht, dann kann dieser letzter Schritt in einem eigenen Microservices implementiert werden. Der Microservice kann dann isoliert von anderen Microservices skaliert werden. Der Microservice gehört zum fachlichen Kontext des Bestellprozess, aber ist aus technischen Gründen als eigener Microservice umgesetzt.

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:

Der

Betrieb

eines Microservices-Systems ist aufwendiger als der Betrieb eines Deployment-Monolithen. Das liegt daran, dass in einem Microservice-System viel mehr deploybare Einheiten existieren, die alle deployt und gemonitort werden müssen. Das ist nur machbar, wenn der Betrieb weitgehend automatisiert ist und die korrekte Funktion durch entsprechendes Monitoring sichergestellt wird.

Teil III

zeigt verschiedene Lösungen dafür.

Microservices müssen tatsächlich

getrennt deploybar

sein. Eine Aufteilung beispielsweise in Docker-Container ist dafür eine Voraussetzung, reicht alleine aber nicht aus. Auch das Testen muss getrennt werden. Wenn alle Microservices zusammen getestet werden müssen, dann kann ein Microservice den Test-Stage blockieren und andere Microservices können nicht deployt werden. Änderungen an Schnittstellen müssen so umgesetzt werden, dass ein unabhängiges Deployment der Microservices immer noch möglich ist. Der Microservice, der die Schnittstelle implementiert, muss beispielsweise die neue und die alte Schnittstelle anbieten, sodass er deployt werden kann, ohne dass der aufrufende Microservice zur selben Zeit deployt werden muss.

Änderungen, die mehrere Microservices

betreffen, sind schwieriger umzusetzen als Änderungen, die mehrere Module eines Deployment-Monolithen umfassen. In einem Microservices-System sind für solche Änderungen mehrere Deloyments notwendig. Diese Deployments müssen koordiniert werden. Bei einem Deployment-Monolithen wäre nur ein Deployment notwendig.

In einem Microservices-System kann die

Übersicht

über die Microservices verloren gehen. Die Erfahrung zeigt allerdings, dass in der Praxis Änderungen bei einem guten fachlichen Schnitt auf einen oder wenige Microservices begrenzt werden können. Daher kommt einem Überblick über das System eine geringere Bedeutung zu, weil die Interaktion der Microservices die Entwicklung wegen der hohen Unabhängigkeit kaum beeinflusst.

1.3.1Vorteile und Nachteile abwägen

Wichtig ist vor allem, dass Microservices nur genutzt werden sollten, wenn sie in einem Szenario die einfachste Lösung sind. Die oben genannten Vorteile sollten die Nachteile beispielsweise wegen der höheren Komplexität im Deployment mehr als wett machen. Schließlich ist es kaum sinnvoll, absichtlich eine zu komplexe Lösung zu nutzen.

1.4Independent-Systems-Architecture-Prinzipien (ISA)

ISA (http://isa-principles.org) (Independent Systems Architecture) ist eine Sammlung von grundlegenden Prinzipien für Microservices. Sie basiert auf Erfahrungen mit Microservices in vielen verschiedenen Projekten.

1.5Bedingungen

Bei den Prinzipien wird »muss« verwendet für Prinzipien, die unbedingt eingehalten werden müssen. »Sollte« beschreibt Prinzipien, die viele Vorteile haben, aber nicht unbedingt eingehalten werden müssen.

1.6Prinzipien

Das System muss in

Module

unterteilt werden, die

Schnittstellen

bieten. Der Zugriff auf andere Module ist nur über diese Schnittstellen möglich. Module dürfen daher nicht direkt von den Implementierungsdetails eines anderen Moduls abhängen, wie z.B. dem Datenmodell in der Datenbank.

Module müssen

separate Prozesse, Container oder virtuelle Maschinen

sein, um die Unabhängigkeit zu maximieren.

Das System muss zwei klar getrennte Ebenen von Architekturentscheidungen haben:

Die

Makro-Architektur

umfasst Entscheidungen, die alle Module betreffen. Alle weiteren Prinzipien sind Teil der Makro-Architektur.

Die

Mikro-Architektur

sind jene Entscheidungen, die für jedes Modul anders getroffen werden können.

Die Wahl der

Integrations-Optionen

muss für das System begrenzt und standardisiert sein. Die Integration kann mit synchroner oder asynchroner Kommunikation stattfinden und/oder auf Frontend-Ebene.

Kommunikation

muss auf einige Protokolle wie REST oder Messaging begrenzt sein. Auch Metadaten, z.B. zur Authentifizierung, müssen standardisiert sein.

Jedes Modul muss seine

eigene unabhängige Continuous-Delivery-Pipeline

haben. Tests sind Teil der Continuous-Delivery-Pipeline, so dass die Tests der Module unabhängig sein müssen.

Der

Betrieb

sollte standardisiert werden. Dies beinhaltet Konfiguration, Deployment, Log-Analyse, Tracing, Monitoring und Alarme. Es kann Ausnahmen vom Standard geben, wenn ein Modul sehr spezifische Anforderungen hat.

Standards

für Betrieb, Integration oder Kommunikation sollten auf Schnittstellenebene definiert werden. Das Protokoll kann als REST standardisiert sein, und Datenstrukturen können standardisiert werden. Aber jedes Modul sollte frei sein, eine andere REST-Bibliothek zu verwenden.

Module müssen

resilient

sein. Sie dürfen nicht ausfallen, wenn andere Module nicht verfügbar sind oder Kommunikationsprobleme auftreten. Sie müssen in der Lage sein, heruntergefahren zu werden, ohne Daten oder Zustand zu verlieren. Es muss möglich sein, sie auf andere Umgebungen (Server, Netzwerke, Konfigurationen usw.) zu verschieben.

1.7Bewertung

Independent Systems Architecture und die Konzepte in diesem Buch haben viele Gemeinsamkeiten. Auch dieses Buch definiert Microservices als Module (Prinzip 1), die unabhängig deploybar sind. Unabhängiges Deployment kann nur durch Container und ähnliche Mechanismen sichergestellt werden (Prinzip 2). Prinzip 6 (unabhängige Deployment Pipelines) führt das unabhängige Deployment weiter aus.

Kapitel 2 betrachtet Mikro- und Makro-Architektur (Prinzip 3) näher. Gerade Integration (Prinzip 4) und Kommunikation (Prinzip 5) sind wichtige Eckpunkte dieses Kapitels. Ebenso spielt der Betrieb (Prinzip 6 und 8) auch in diesem Buch eine wichtige Rolle. Die Technologien sind meistens standardisiert. Kapitel 2 diskutiert Gründe für die Standardisierung und Ausnahmen noch genauer. Schließlich kann das Ziel der Robustheit, auf das dieses Kapitel schon eingegangen ist, nur mit Resilience (Prinzip 9) erreicht werden.

Die ISA-Prinzipien stellen also eine gute Zusammenfassung der Prinzipien aus diesem Kapitel und der Ideen zur Mikro- und Makro-Architektur aus diesem Buch dar.

1.8Variationen

Abhängig vom konkreten Szenario können Microservices-Varianten wie Self-contained Systems (siehe Kapitel 3) genutzt werden.

1.8.1Technologische Varationen

Teil II (ab Kapitel 5) und Teil III (ab Kapitel 19) des Buches zeigen unterschiedliche technologische Variationen. Dazu zählen synchrone Kommunikation, asynchrone Kommunikation und UI-Integration. Die Kombination von einem oder mehrerer Rezepte aus diesen Teilen ergibt eine individuelle Microservices-Architektur.

1.8.2Experimente

Das folgende Vorgehen hilft dabei, die richtigen Rezepte zu finden:

Priorisiere für ein dir bekanntes Projekt die Vorteile des Einsatzes von Microservices.

Wäge ab, welche der Herausforderungen in dem Projekt ein hohes Risiko darstellen könnten.

Anschließend können die möglichen technischen und architekturellen Lösungen dagegen abgewogen werden, ob sie bei diesen Anforderungen eine sinnvolle Lösung darstellen.

Für eine konkrete Aufteilung der Microservices und technische Entscheidungen sind zusätzliche Konzepte notwendig. Daher steht die Aufteilung im Mittelpunkt von Abschnitt 2.6.

1.9Fazit

Microservices sind eine extreme Art der Modularisierung. Das getrennten Deployment ist die Grundlage für eine sehr starke Entkopplung.

Daraus ergeben sich zahlreiche Vorteile. Ein wesentlicher Vorteil ist Isolation in verschiedenen Ebenen. Das vereinfacht nicht nur das Deployment, sondern auch ein Ausfall kann auf einen Microservice begrenzt werden. Microservices können einzeln skaliert werden, Technologie-Entscheidungen haben nur Auswirkungen auf einen Microservice und auch ein Sicherheitsproblem kann auf einen Microservice begrenzt werden. Durch die Isolation kann ein Microservices-System mit einem großen Team einfacher entwickelt werden, weil weniger Koordination zwischen den Teams notwendig ist. Und natürlich sorgen die kleineren Deployment-Artefakte dafür, dass Continuous Delivery einfacher umgesetzt werden kann. Die Ablösung eines Legacy-Systems kann mit Microservices ebenfalls einfacher erfolgen, weil neue Microservices das System ergänzen können, ohne dass dazu größere Änderungen am Code notwendig wären.

Die Herausforderungen liegen vor allem im Betrieb. Mit passenden technologischen Entscheidungen sollten die beabsichtigten Vorteile verstärkt und gleichzeitig die Nachteile minimiert werden.

Die Integration und Kommunikation zwischen den Microservices ist natürlich komplexer als die Aufrufe zwischen Modulen in einem Deployment-Monolithen. Die zusätzliche technische Komplexität stellt eine weitere wichtige Herausforderung bei Microservice-Architekturen dar.

2Mikro- und Makro-Architektur

Microservices erlauben es, durch die Isolation auf verschiedenen Ebenen Software noch stärker zu modularisieren und zu isolieren (siehe Abschnitt 1.2). Aber Microservices sind Module eines Gesamtsystems. Also müssen sie integriert werden. Die Architektur steht damit vor einer Herausforderung: Auf der einen Seite muss sichergestellt werden, dass die Microservices als Teile des Gesamtsystems zusammenpassen. Auf der anderen Seite dürfen die Freiheiten in den Microservices nicht zu sehr eingeschränkt werden, weil sonst die Isolation und die Unabhängigkeit der Microservices nicht erreicht werden können, die für die meisten Vorteile der Microservices-Architektur verantwortlich sind.

Daher bietet es sich an, die Architektur in eine Mikro- und eine Makro-Architektur aufzuteilen. Die Mikro-Architektur umfasst alle Entscheidungen, die für jeden Microservices anders getroffen werden können. Die Makro-Architektur beinhaltet die Entscheidungen, die global getroffen werden und für alle Microservices gelten.

Abb. 2–1Mikro- und Makro-Architektur

Abbildung 2–1 zeigt die Idee: Es gibt eine Makro-Architektur, die für alle Microservices übergreifend gilt. Die Mikro-Architektur gilt jeweils für einen Microservices, sodass jeder Microservice seine eigene Mikro-Architektur hat.

Dieses Kapitel zeigt das Vorgehen für eine solche Architektur-Aufteilung:

Zunächst vermittelt das Kapitel die

fachliche Aufteilung

in Microservices und zeigt, dass

Domain-driven Design

und

Bounded Context

gute Werkzeuge für eine solche Aufteilung sind.

Dann erläutert das Kapitel die Entscheidungen, die im Rahmen der

technischen Mikro- und Makro-Architektur

getroffen werden müssen und wie ein

DevOps-Modell

die Entscheidungen beeinflusst.

Schließlich wird die Frage beantwortet,

wer

die Aufteilung in Mikro- und Makro-Architektur vornimmt und die Regeln in der Makro-Architektur festlegt.

2.1Bounded Context und Strategic Design

Bei der fachlichen Aufteilung ist das Konzept von Mikro- und Makro-Architektur schon lange üblich: Es gibt eine Makro-Architektur, welche die Fachlichkeit in grobgranulare Module aufteilt. In den Modulen erfolgt eine weitere Aufteilung als Mikro-Architektur.

So kann beispielsweise ein ECommerce-Systeme in Module für die Registrierung von Kunden und für die Annahme von Bestellungen unterteilt werden. Die Annahme der Bestellungen kann in weitere kleinere Module zerlegt werden. Das können beispielsweise die Validierung der Daten oder die Berechnung der Versandkosten sein. Die interne Aufteilung des Registrierungs-Moduls ist nach außen nicht sichtbar und kann geändert werden, ohne dass es andere Module beeinflusst. Genau diese Flexibilität, ein Modul ohne Beeinflussung anderer Module zu ändern, ist ein wesentlicher Vorteil der modularen Software-Entwicklung.

2.1.1Ein Beispiel für eine fachliche Architektur

Abb. 2–2Beispiel für eine fachliche Aufteilung

Abbildung 2–2 zeigt ein Beispiel für eine Aufteilung eines Systems in mehrere fachliche Module. In dieser Aufteilung hat jedes Modul ein eigenes Domänenmodell:

Für die

Suche

müssen für Produkte Daten wie Beschreibungen, Bilder oder Preise abgelegt sein. Für die Kunden wären die notwendigen Daten die Empfehlungen, die z.B. aus den bereits abgearbeiteten Bestellungen ermittelt werden können.

Der

Check Out

muss Buch darüber führen, was im Einkaufswagen liegt. Für Produkte sind nur grundlegende Informationen wie ein Name oder der Preis notwendig. Ebenso sind nur wenige Daten über den Kunden notwendig. Wichtigster Bestandteil des Domänenmodells dieses Moduls ist der Einkaufswagen.

Für

Inkasso

müssen vom Kunden die Bezahlweise und die dafür notwendigen Informationen wie die Kreditkartennummer bekannt sein.

Bei der

Lieferung

sind vom Kunden die Lieferadresse und von den Produkten Größe und Gewicht notwendig.

In dieser Aufstellung kann man erkennen, dass für die verschiedenen Module unterschiedliche Domänenmodelle notwenig sind. Nicht nur die Daten für Kunde und Produkt unterscheiden sich, sondern das gesamte Modell und auch die Logik.

2.1.2Domain-driven Design: Definition

Für die fachliche Modellierung eines Systems bietet Domain-driven Design (DDD) eine Sammlung von Patterns. Für Microservices sind vor allem die Patterns im Bereich von Strategic Design interessant. Sie beschreiben, wie eine Domäne unterteilt werden kann. Domain-driven Design bietet noch viel mehr Patterns, die z.B. bei der Bildung einzelner Modelle helfen können. Für einen tieferen Einstieg empfiehlt sich das ursprüngliche DDD-Buch,1 das den Begriff Domain-driven Design eingeführt hat und DDD umfassend beschreibt, oder das kompakte DDD-Buch,2 das vor allem auf Strategic Design, Bounded Context und Domain Events fokussiert.

2.1.3Bounded Context: Definition

Domain-driven Design spricht von einem Bounded Context: Jedes Domänenmodell ist nur in einem begrenzten Kontext gültig. Suche, Check Out, Inkasso und Lieferung sind also solche Bounded Contexts, weil sie jeweils ein eigenes Domänenmodell haben.

Es wäre zwar denkbar, ein Domänenmodell umzusetzen, dass mehrere Bounded Contexts aus dem Beispiel umfasst. Aber ein solches Modell wäre nicht die einfachste Lösung. Beispielsweise muss eine Preisänderung eines Produkts sich auf die Suche auswirken, aber es darf nicht dazu führen, dass im Inkasso bereits getätigte Bestellungen teurer werden. Es ist einfacher, in der Suche nur den aktuellen Preis eines Produkts zu speichern und im Inkasso den Preis des Produkts in jeder Bestellung zu speichern, der auch Rabatte und andere komplexe Einflussfaktoren beinhalten kann. Der einfachste Entwurf besteht also aus mehreren spezialisierten Domänenmodellen, die jeweils nur in einem Kontext gültig sind. Jedes der Domänenmodelle hat eine eigene Modellierung für Geschäftsobjekte wie Kunden oder Produkte.

2.1.4Strategic Design

Die Aufteilung des Systems in verschiedene Bounded Contexts ist ein Teil des Strategic Designs, das zu den Praktiken aus dem Domain-driven Design (DDD) gehört. Das Strategic Design beschreibt die Integration von Bounded Contexts.

Abb. 2–3Strategic-Design-Grundlagen

Abbildung 2–3 zeigt die grundlegenden Begriffe im Strategic Design:

Die

Bounded Contexts

beschreiben jeweils den Gültigkeitsbereich eines

Domänenmodells

.

Die Bounded Contexts können miteinander kommunizieren: Der

Upstream

(deutsch: vorgeschaltet) Bounded Context stellt dem

Downstream

(deutsch: nachgeschaltet) Bounded Context Informationen zur Verfügung. Technisch kann der Upstream Bounded Context neue Informationen an den Downstream Bounded Context schicken oder der Downstream Bounded Context kann neue Informationen beim Upstream Bounded Context abholen. Die technische Kommunikationsrichtung kann also eine andere sein als die Richtung, in die die Informationen fließen.

2.1.5Strategic Design Patterns

Wie die Kommunikation genau abläuft, beschreibt DDD in verschiedenen Patterns. Diese Patterns beschreiben nicht nur einen Ansatz auf der ArchitekturEbene, sondern auch das Miteinander auf organisatorischer Ebene:

Conformist

(Konformist) bedeutet, dass ein Bounded Context ein Domänenmodell von einem anderen Bounded Context einfach übernimmt. In

Abbildung 2–4

benutzen Bounded Context 1 und 2 jeweils dasselbe Domänenmodell 1. Ein Beispiel können Statistiken als Teil eines Data Warehouses sein. Sie nutzen das Domänenmodell aus den anderen Bounded Contexts und extrahieren die für sie interessanten Daten. Ein Mitspracherecht bei Änderungen am Bounded Context haben sie beim Conformist-Pattern nicht.

Abb. 2–4Conformist: Domänenmodell wird übernommen

Bei einem

Anti-corruption Layer

(Antikorruptionsschicht, ACL) enthält der Downstream Bounded Context eine Schicht, um das eigene Domänenmodell vom Modell des Upstream Bounded Contexts zu entkoppeln. Das ist insbesondere zusammen mit Conformist sinnvoll, um so ein eigenes, vom anderen Modell entkoppeltes Modell zu erstellen. In

Abbildung 2–5