Eberhard Wolff arbeitet seit mehr als 15 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.
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 |
Grundlagen flexibler Softwarearchitekturen
2., aktualisierte Auflage
Eberhard Wolff
eberhard.wolff@gmail.com
Lektorat: René Schönfeldt
Copy-Editing: Sandra Gottmann (Münster-Nienberge)
Satz: Nadine Thiele
Herstellung: Susanne Bröckelmann
Umschlaggestaltung: Helmut Kraus, www.exclam.de
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:
Print978-3-86490-555-1
PDF978-3-96088-413-2
ePub978-3-96088-414-9
mobi978-3-96088-415-6
2., aktualisierte 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 0
1Vorwort
1.1Überblick über Microservices
1.2Warum Microservices?
Teil IMotivation und Grundlagen
2Einleitung
2.1Überblick über das Buch
2.2Für wen ist das Buch?
2.3Übersicht über die Kapitel
2.4Essays
2.5Pfade durch das Buch
2.6Danksagung
2.7Änderungen in der 2. Auflage
2.8Links & Literatur
3Microservice-Szenarien
3.1Eine E-Commerce-Legacy-Anwendung modernisieren
3.2Ein neues Signalsystem entwickeln
3.3Fazit
Teil IIMicroservices: Was, warum und warum vielleicht nicht?
4Was sind Microservices?
4.1Größe eines Microservice
4.2Das Gesetz von Conway
4.3Domain-Driven Design und Bounded Context
4.4Self-contained Systems
4.5Fazit
4.6Links & Literatur
5Gründe für Microservices
5.1Technische Vorteile
5.2Organisatorische Vorteile
5.3Vorteile aus Geschäftssicht
5.4Fazit
5.5Links & Literatur
6Herausforderungen bei Microservices
6.1Technische Herausforderungen
6.2Architektur
6.3Infrastruktur und Betrieb
6.4Fazit
6.5Links & Literatur
7Microservices und SOA
7.1Was ist SOA?
7.2Unterschiede zwischen SOA und Microservices
7.3Fazit
7.4Links & Literatur
Teil IIIMicroservices umsetzen
8Architektur von Microservice-Systemen
8.1Fachliche Architektur
8.2Architekturmanagement
8.3Techniken zum Anpassen der Architektur
8.4Microservice-Systeme weiterentwickeln
8.5Microservice und Legacy-Anwendung
8.6Event-driven Architecture
8.7Technische Architektur
8.8Konfiguration und Koordination
8.9Service Discovery
8.10Load Balancing
8.11Skalierbarkeit
8.12Sicherheit
8.13Dokumentation und Metadaten
8.14Fazit
8.15Links & Literatur
9Integration und Kommunikation
9.1Web und UI
9.2REST
9.3SOAP und RPC
9.4Messaging
9.5Datenreplikation
9.6Schnittstellen: intern und extern
9.7Fazit
9.8Links & Literatur
10Architektur eines Microservice
10.1Fachliche Architektur
10.2CQRS
10.3Event Sourcing
10.4Hexagonale Architekturen
10.5Resilience und Stabilität
10.6Technische Architektur
10.7Fazit
10.8Links & Literatur
11Testen von Microservices und Microservice-Systemen
11.1Warum testen?
11.2Wie testen?
11.3Risiken beim Deployment minimieren
11.4Tests des Gesamtsystems
11.5Legacy-Anwendungen mit Microservices testen
11.6Tests einzelner Microservices
11.7Consumer-Driven Contract Test
11.8Technische Standards testen
11.9Fazit
11.10Links & Literatur
12Betrieb und Continuous Delivery von Microservices
12.1Herausforderungen beim Betrieb von Microservices
12.2Logging
12.3Monitoring
12.4Deployment
12.5Steuerung
12.6Infrastrukturen
12.7Fazit
12.8Links & Literatur
13Organisatorische Auswirkungen der Architektur
13.1Organisatorische Vorteile von Microservices
13.2Alternativer Umgang mit dem Gesetz von Conway
13.3Spielräume schaffen: Mikro- und Makro-Architektur
13.4Technische Führung
13.5DevOps
13.6Schnittstelle zu den Fachbereichen
13.7Wiederverwendbarer Code
13.8Microservices ohne Organisationsänderung?
13.9Fazit
13.10Links & Literatur
Teil IVTechnologien
14Beispiel-Implementierung von Microservices
14.1Fachliche Architektur
14.2Basistechnologien
14.3Build
14.4Deployment mit Docker
14.5Docker Machine
14.6Docker Compose
14.7Service Discovery
14.8Routing
14.9Resilience
14.10Load Balancing
14.11Integration anderer Technologien
14.12Tests
14.13Weitere Beispiele
14.14Fazit
14.15Links & Literatur
15Technologien für Nanoservices
15.1Warum Nanoservices?
15.2Definition Nanoservice
15.3Amazon Lambda
15.4OSGi
15.5Java EE
15.6Vert.x
15.7Erlang
15.8Seneca
15.9Fazit
15.10Links & Literatur
16Wie mit Microservices loslegen?
16.1Warum Microservices?
16.2Wege zu Microservices
16.3Microservice: Hype oder Realität?
16.4Fazit
Index
Microservices sind ein neuer Begriff – aber sie verfolgen mich schon lange. 2006 hielt Werner Vogels (CTO, Amazon) einen Vortrag auf der JAOO-Konferenz, wo er die Amazon Cloud und Amazons Partnermodell vorstellte [1]. Dabei erwähnte er das CAP-Theorem – heute Basis für NoSQL. Und dann sprach er von kleinen Teams, die Services mit eigener Datenbank entwickeln und auch betreiben. Diese Organisation nennen wir heute DevOps und die Architektur Microservices.
Später sollte ich für einen Kunden eine Strategie entwickeln, wie er moderne Technologien in seine Anwendung integrieren kann. Nach einigen Versuchen, neue Technologien direkt in den Legacy-Code zu integrieren, haben wir schließlich eine neue Anwendung neben der alten Anwendung mit einem völlig anderen modernen Technologie-Stack aufgebaut. Die neue und die alte Anwendung waren nur über HTML-Links gekoppelt – und über die gemeinsame Datenbank. Bis auf die gemeinsame Datenbank ist auch dieses Vorgehen im Kern ein Microservices-Ansatz. Das war 2008.
Ein anderer Kunde hatte schon 2009 seine komplette Infrastruktur in REST-Services aufgeteilt, die jeweils von einzelnen Teams weiterentwickelt wurden. Auch das nennen wir heute Microservices. Viele andere Unternehmen aus dem Internet-Bereich hatten damals schon ähnliche Architekturen.
In letzter Zeit wurde mir außerdem klar, dass Continuous Delivery [2] Auswirkungen auf die Software-Architektur hat. Auch in diesem Bereich haben Microservices viele Vorteile.
Und das ist der Grund für das Buch: Microservices sind ein Ansatz, den einige schon sehr lange verfolgen; darunter auch viele sehr erfahrene Architekten. Wie jeder Architekturansatz löst er sicher nicht alle Probleme – aber er kann eine interessante Alternative darstellen.
Microservice: vorläufige Definition
Im Mittelpunkt des Buchs stehen Microservices – ein Ansatz zur Modularisierung von Software. Modularisierung ist nichts Neues. Schon lange werden große Systeme in kleine Module unterteilt, um Software einfacher zu erstellen, zu verstehen und weiterzuentwickeln.
Das Neue: Microservices nutzen als Module einzelne Programme, die als eigene Prozesse laufen. Der Ansatz basiert auf der UNIX-Philosophie. Sie lässt sich auf drei Aspekte reduzieren:
Der Begriff Microservice ist nicht fest definiert. Kapitel 4 zeigt eine genauere Definition. Als erste Näherung dienen folgende Kriterien:
Dieser Ansatz betrachtet die Größe des Microservice nicht. Trotz des Namens »Microservice« ist die Größe für eine grobe Definition nicht so entscheidend.
Monolithen
Microservices grenzen sich von Deployment-Monolithen ab. Ein Deployment-Monolith ist ein großes Software-System, das nur als Ganzes auf einmal deployt werden kann. Es muss als Ganzes durch alle Phasen der Continuous-Delivery-Pipeline wie Deployment, Test, Abnahme und Release laufen. Durch die Größe des Deployment-Monolithen dauert dieser Prozess länger als bei kleineren Systemen. Das reduziert die Flexibilität und erhöht die Kosten der Prozesse. Der Deployment-Monolith kann intern modular aufgebaut sein – nur müssen alle diese Module gemeinsam in Produktion gebracht werden.
Microservices dienen dazu, Software in Module aufzuteilen und dadurch die Änderbarkeit der Software zu verbessern.
Microservices haben einige wesentliche Vorteile:
Starke Modularisierung
Leichte Ersetzbarkeit
Nachhaltige Software-Entwicklung
Legacy-Anwendung erweitern
Time-to-Market
Unabhängige Skalierung
Technologiefreiheit
Continuous Delivery
Alle diese Gründe sprechen für die Einführung von Microservices. Welche Gründe am wichtigsten sind, hängt von dem Szenario ab. Die Skalierung agiler Prozesse und Continuous Delivery sind oft aus einer Geschäftssicht wichtig. Kapitel 5 widmet sich den Vorteilen von Microservices im Detail und geht auch auf die Priorisierung ein. Wo so viel Licht ist, ist auch Schatten. Daher wird Kapitel 6 noch detailliert darlegen, welche Herausforderungen bei der Umsetzung von Microservices existieren und wie man mit ihnen umgehen kann. Im Wesentlichen sind das die folgenden:
Beziehungen sind versteckt.
Refactoring ist schwierig.
Fachliche Architektur ist wichtig.
Betrieb ist komplex.
Verteilte Systeme sind komplex.
[1]http://jandiandme.blogspot.com/2006/10/jaoo-2006-werner-vogelscto-amazon.html
[2]Eberhard Wolff: Continuous Delivery: Der pragmatische Einstieg, dpunkt.verlag, 2014, ISBN 978-3864902086
Dieser Teil des Buchs zeigt, was Microservices sind, warum Microservices so interessant sind und wo sie gewinnbringend genutzt werden können. So wird an praktischen Beispielen klar, was Microservices in welchen Szenarien bewirken.
Kapitel 2 erläutert die Struktur des Buchs. Um die Bedeutung von Microservices zu illustrieren, enthält Kapitel 3 konkrete Szenarien für die Nutzung von Microservices.
In diesem Kapitel steht das Buch selber im Mittelpunkt: Abschnitt 2.1 beschreibt kurz das Konzept des Buchs, Abschnitt 2.2 beschreibt die Zielgruppe und Abschnitt 2.3 gibt einen Überblick über die Kapitel und Struktur des Buchs. Abschnitt 2.4 erläutert die Bedeutung der Essays im Buch. Abschnitt 2.5 beschreibt Pfade durch das Buch für die verschiedenen Zielgruppen und Abschnitt 2.6 enthält schließlich die Danksagung.
Errata, Links zu den Beispielen und weitere Informationen finden sich unter http://microservices-buch.de/.
Das Buch gibt eine ausführliche Einleitung in Microservices. Dabei stehen die Architektur und Organisation im Mittelpunkt, ohne dass technische Umsetzungsmöglichkeiten vernachlässigt werden. Ein vollständig implementiertes Beispiel für ein Microservice-System zeigt eine konkrete technische Umsetzung. Technologien für Nanoservices zeigen, dass es sogar noch kleiner als Microservices geht. Das Buch vermittelt alles, um mit dem Umsetzen von Microservices loszulegen.
Das Buch wendet sich an Manager, Architekten und Techniker, die Microservices als Architekturansatz einführen wollen.
Manager
Entwickler
Architekten
Im Buch gibt es Hinweise für eigene Experimente und Möglichkeiten zur Vertiefung. So kann der Interessierte das Gelesene praktisch ausprobieren und sein Wissen selbstständig erweitern.
Teil I
Der erste Teil des Buchs zeigt die Motivation für Microservices und die Grundlagen der Microservices-Architektur. Das Kapitel 1 hat schon die grundlegenden Eigenschaften, Vor- und Nachteile von Microservices erläutert. Kapitel 3 zeigt zwei Szenarien für den Einsatz von Microservices: eine E-Commerce-Anwendung und ein System zur Verarbeitung von Signalen. Dieser Teil vermittelt einen ersten Einblick von Microservices und zeigt auch schon Anwendungskontexte.
Teil II
Teil II erläutert nicht nur Microservices genauer, sondern beschreibt auch die Vor- und Nachteile:
Teil III
Im Teil III geht es um die Umsetzung von Microservices. Der Teil zeigt, wie die Vorteile aus Teil II erreicht werden und wie die Herausforderungen gelöst werden können.
Teil IV
Der letzte Teil des Buchs zeigt, wie Microservices ganz konkret technisch umgesetzt werden können. Dort geht es dann hinunter bis auf die Code-Ebene:
Das Buch enthält Essays, die Microservices-Experten geschrieben haben. Die Aufgabe war, auf ungefähr zwei Seiten wichtige Erkenntnisse zu Microservices festzuhalten. Manchmal ergänzen die Essays das Buch, manchmal beleuchten sie andere Themen und manchmal widersprechen sie auch dem Rest des Buchs. Es gibt eben bei Software-Architekturen oft keine klaren Antworten, sondern verschiedene Meinungen und Möglichkeiten. Die Essays bieten die Chance, verschiedene Standpunkte kennenzulernen, um sich dann eine eigene Meinung zu bilden.
Das Buch bietet für jede Zielgruppe passende Inhalte (siehe Tab. 2–1). Natürlich kann und sollte jeder auch Kapitel lesen, die vielleicht nicht zur eigenen Rolle gehören. Aber der Fokus der Kapitel liegt auf der jeweiligen Rolle.
Kapitel |
Entwickler |
Architekten |
Manager |
3 – Microservice-Szenarien |
X |
X |
X |
4 – Was sind Microservices? |
X |
X |
X |
5 – Gründe für Microservices |
X |
X |
X |
6 – Herausforderungen bei Microservices |
X |
X |
X |
7 – Microservices und SOA |
|
X |
X |
8 – Architektur von Microservice-Systemen |
|
X |
|
9 – Integration und Kommunikation |
X |
X |
|
10 – Architektur eines Microservice |
X |
X |
|
11 – Testen von Microservices und Microservice-Systemen |
X |
X |
|
12 – Betrieb und Continuous Delivery von Microservices |
X |
X |
|
13 – Organisatorische Auswirkungen der Architektur |
|
|
X |
14 – Beispiel-Implementierung von Microservices |
X |
|
|
15 – Technologien für Nanoservices |
X |
X |
|
16 – Wie mit Microservices loslegen? |
X |
X |
X |
Wer nur an dem groben Inhalt eines Kapitels interessiert ist, kann das Fazit des Kapitels lesen. Wer direkt ganz praktisch einsteigen will, sollte mit den Kapiteln 14 und 15 anfangen, bei denen konkrete Technologien und Code im Mittelpunkt stehen.
Die Anleitungen zu eigenen Experimenten in den Abschnitten »Selber ausprobieren und experimentieren« können die Basis zu einer selbstständigen Vertiefung des Gelernten sein. Wenn ein Kapitel besonders wichtig erscheint, kann man die Aufgaben dazu durcharbeiten, um die Themen des Kapitels genauer kennenzulernen.
Alle, mit denen ich das diskutiert habe, die Fragen gestellt oder mit mir zusammengearbeitet haben – viel zu viele, um sie alle zu nennen. Der Dialog hilft sehr und macht Spaß!
Besonders erwähnen möchte ich Jochen Binder, Matthias Bohlen, Merten Driemeyer, Martin Eigenbrodt, Oliver B. Fischer, Lars Gentsch, Oliver Gierke, Boris Gloger, Alexander Heusingfeld, Christine Koppelt, Andreas Krüger, Tammo van Lessen, Sascha Möllering, André Neubauer, Till Schulte-Coerne, Stefan Tilkov, Kai Tödter, Oliver Wolf und Stefan Zörner
Eine wichtige Rolle hat auch mein Arbeitgeber, die innoQ, gespielt. Viele Diskussionen und Anregungen meiner Kollegen finden sich in diesem Buch.
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.
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.
In der zweiten Auflage ist vor allem der Abschnitt 4.3 zu DDD komplett überarbeitet. DDD ist eine wichtige Basis für Microservices, sodass eine bessere Erläuterung sinnvoll ist. Das Beispiel in Kapitel 14 ist komplett überarbeitet, da sich die Technologien weiterentwickeln und mittlerweile neben dem Netflix-Stack auch Alternativen verfügbar sind, die nun in Kapitel 14, aber auch im Rest des Buchs Erwähnung finden.
[1]Eberhard Wolff: Continuous Delivery: Der pragmatische Einstieg, dpunkt.verlag, 2. Auflage, 2016, ISBN 978-3-86490-371-7
Dieses Kapitel zeigt einige Szenarien, in denen die Nutzung von Microservices sinnvoll ist. Abschnitt 3.1 betrachtet die Modernisierung einer Legacy-Webanwendung. Dieses Szenario ist der häufigste Einsatzkontext von Microservices. Ein völlig anderes Szenario stellt Abschnitt 3.2 vor. Dort geht es um die Entwicklung eines Signalsystems, das als verteiltes System mit Microservice umgesetzt wird. Abschnitt 3.3 zieht ein Fazit aus den Szenarien und lädt zu einer eigenen Bewertung ein.
Die Raffzahn Online Commerce GmbH betreibt einen E-Commerce-Shop, von dem der Umsatz des Unternehmens wesentlich abhängt. Es ist eine Webanwendung, die sehr viele unterschiedliche Funktionalitäten anbietet. Dazu zählen die Benutzerregistrierung und -verwaltung, Produktsuche, Überblick über die Bestellungen und der Bestellprozess – das zentrale Feature einer E-Commerce-Anwendung.
Diese Anwendung ist ein Deployment-Monolith: Sie kann nur als Ganzes deployt werden. Bei einer Änderung eines Features muss die gesamte Anwendung neu ausgeliefert werden. Der E-Commerce-Shop arbeitet mit anderen Systemen zusammen – beispielsweise der Buchhaltung und der Lagerhaltung.
Der Deployment-Monolith war zwar als wohlstrukturierte Anwendung gestartet, aber über die Jahre haben sich mehr und mehr Abhängigkeiten zwischen den Modulen eingeschlichen. Aus diesem Grund ist die Anwendung mittlerweile kaum noch wart- und änderbar. Außerdem ist die ursprüngliche Architektur schon lange nicht mehr angemessen für die aktuellen Anforderungen. So wurde beispielsweise die Produktsuche sehr stark verändert, weil die Raffzahn Online Commerce GmbH sich vor allem in diesem Bereich von den Konkurrenten abheben will. Ebenso sind mehr und mehr Möglichkeiten geschaffen worden, wie Kunden Probleme ohne Kundenservice selber lösen können. Dadurch konnte die Firma ihre Kosten erheblich reduzieren. Dementsprechend sind diese beiden Module mittlerweile sehr groß, intern sehr komplex aufgebaut und haben auch viele Abhängigkeiten zu anderen Modulen, die ursprünglich nicht eingeplant waren.
Langsame Continuous Delivery Pipeline
Raffzahn setzt auf Continuous Delivery und hat eine Continuous-Delivery-Pipeline etabliert. Die Pipeline ist kompliziert und hat eine lange Durchlaufzeit, weil der komplette Deployment-Monolith getestet und in Produktion gebracht werden muss. Einige der Tests dauern Stunden. Schnellere Durchlaufzeiten durch die Pipeline wären sicher wünschenswert.
Parallele Arbeit ist kompliziert.
Es gibt Teams, die an verschiedenen neuen Features arbeiten. Aber die parallele Arbeit ist kompliziert: Die Struktur der Software ist dafür zu schlecht. Die einzelnen Module sind zu schlecht separiert und haben zu viele Abhängigkeiten untereinander. Da alles nur gemeinsam deployt werden kann, muss der gesamte Deployment-Monolith vorher auch getestet werden. Das Deployment und die Testphase sind ein Flaschenhals. Wenn ein Team gerade ein Release in der Deployment-Pipeline hat, aber bei dem Release in diesen Phasen ein Problem auftaucht, müssen alle anderen Teams warten, bis die Änderung erfolgreich deployt worden ist. Und der Durchlauf durch die Deployment-Pipeline muss koordiniert werden. Nur ein Team kann zu einem Zeitpunkt im Test und Deployment sein. So wird geregelt, welches Team welche Änderung wann in Produktion bringen darf.
Flaschenhals bei den Tests
Neben dem Deployment müssen auch die Tests koordiniert werden. Wenn der Deployment-Monolith durch einen Integrationstest läuft, dürfen in dem Test nur die Änderungen eines Teams enthalten sein. Es gab Versuche, mehrere Änderungen auf einmal zu testen. Dann war bei einem Fehler nicht klar, woher das Problem kam, und es gab lange und komplexe Fehleranalysen.
Ein Integrationstest dauert ca. eine Stunde. Pro Arbeitstag sind realistisch sechs Integrationstests möglich, weil Fehler behoben und die Umgebungen wieder hergerichtet werden müssen. Bei zehn Teams kann ein Team im Schnitt ungefähr alle zwei Tage eine Änderung in Produktion bringen. Oft muss ein Team aber Fehleranalyse betreiben – dann verlängert sich die Integration. Daher nutzen einzelne Teams Feature Branches, um sich von der Integration zu entkoppeln: Sie nehmen ihre Änderungen an einem separierten Zweig in der Versionskontrolle vor. Bei der Integration dieser Änderungen in den Hauptzweig kommt es immer wieder zu Problemen: Änderungen werden aus Versehen beim Mergen wieder entfernt oder die Software hat plötzlich Fehler, die durch die getrennte Entwicklung aufgetreten sind. Die Fehler können erst nach einer Integration in langwierigen Prozessen ausgemerzt werden.
Also bremsen sich die Teams durch die Tests gegenseitig aus. Letztendlich arbeiten alle Teams zwar an den eigenen Modulen, aber an derselben Code-Basis, sodass sie sich ausbremsen. Durch die gemeinsame Continuous-Delivery-Pipeline und die dadurch notwendige Koordination sind letztendlich die Teams nicht dazu in der Lage, unabhängig und parallel zu arbeiten.
Die Raffzahn Online Commerce GmbH hat sich wegen der vielen Probleme dazu entschieden, kleine Microservices von dem Deployment-Monolithen abzuspalten. Die Microservices implementieren jeweils ein Feature wie beispielsweise die Produktsuche und werden von einem Team verantwortet. Das Team ist von der Anforderungsaufnahme bis zum Betrieb der Anwendung vollständig verantwortlich. Diese Microservices kommunizieren mit dem Monolithen und anderen Microservices über REST. Auch die Benutzeroberfläche ist anhand der fachlichen Anwendungsfälle auf die einzelnen Microservices aufgeteilt. Jeder Microservice liefert die HTML-Seiten für seine Anwendungsfälle aus. Zwischen den HTML-Seiten der Microservices darf es Links geben. Aber es ist nicht erlaubt, auf die Datenbanktabellen der anderen Microservices oder des Deployment-Monolithen zuzugreifen. Ein Datenaustausch zwischen den Services darf ausschließlich über REST oder durch die Verlinkung der HTML-Seiten erfolgen.
Die Microservices können unabhängig voneinander deployt werden. Dadurch ist es möglich, Änderungen in den Microservices ohne Koordinierung mit anderen Microservices oder Teams auszuliefern. Das vereinfacht die parallele Arbeit an Features erheblich und reduziert gleichzeitig den Koordinierungsaufwand.
Der Deployment-Monolith ist durch die Ergänzung um die Microservices wesentlich weniger Änderungen unterworfen. Für viele Features sind gar keine Änderungen am Monolithen mehr notwendig. Daher wird der Deployment-Monolith nun seltener deployt und geändert. Eigentlich war der Plan, den Deployment-Monolithen irgendwann vollständig abzulösen. Aber mittlerweile erscheint es wahrscheinlich, dass der Deployment-Monolith einfach zunehmend seltener deployt wird, weil die meisten Änderungen in den Microservices stattfinden. Dann stört der Deployment-Monolith aber nicht mehr. Eine vollständige Ablösung ist eigentlich überflüssig und erscheint wirtschaftlich nicht mehr sinnvoll.
Durch die Umsetzung der Microservices entsteht zunächst zusätzliche Komplexität: Die vielen Microservices benötigen eigene Infrastrukturen. Parallel muss der Monolith weiter unterstützt werden.
Die Microservices umfassen wesentlich mehr Server und stellen daher ganz andere Anforderungen. Das Monitoring und die Verarbeitung der Logdateien müssen damit umgehen, dass die Daten auf verschiedenen Servern anfallen. Also müssen die Informationen zentral konsolidiert werden. Außerdem muss eine wesentlich größere Anzahl Server angeboten werden – und zwar nicht nur in Produktion, sondern auch in den verschiedenen Test-Stages und auch Umgebungen für die einzelnen Teams sind sie notwendig. Das stellt wesentlich höhere Anforderungen an die Infrastruktur-Automatisierung. Es müssen nicht nur zwei unterschiedliche Arten von Infrastrukturen für den Monolithen und die Microservices unterstützt werden, sondern unter dem Strich auch wesentlich mehr Server.
Vollständige Migration ist langwierig.
Die zusätzliche Komplexität durch die beiden unterschiedlichen Software-Arten wird sehr lange vorhanden sein, denn die vollständige Migration weg vom Monolithen ist ein langwieriger Prozess. Wenn der Monolith niemals vollständig abgelöst wird, werden auch die zusätzlichen Infrastrukturkosten bestehen bleiben.
Testen bleibt eine Herausforderung.
Eine weitere Herausforderung ist das Testen: Bisher wurde der gesamte Deployment-Monolith in der Deployment-Pipeline getestet. Diese Tests sind aufwendig und dauern lange, weil sie alle Funktionalitäten im Deployment-Monolithen testen müssen. Wenn jede Änderung an jedem Microservice durch diese Tests geschickt wird, dauert es sehr lange, bis die Änderungen in Produktion sind. Außerdem müssen die Änderungen koordiniert werden, denn jede Änderung sollte einzeln getestet werden, damit gegebenenfalls klar ist, welche Änderung einen Fehler ausgelöst hat. Damit ist dann gegenüber dem Deployment-Monolithen nicht viel gewonnen: Das Deployment wäre zwar unabhängig voneinander möglich, aber die Test-Stages vor dem Deployment müssen immer noch koordiniert und von jeder Änderung einzeln durchlaufen werden.
Aktueller Stand der Migration
Abbildung 3–2 zeigt den aktuellen Stand: Die Produktsuche arbeitet auf ihrem eigenen Microservice und vollständig unabhängig vom Deployment-Monolithen. Eine Koordinierung mit den anderen Teams ist kaum noch notwendig. Nur im letzten Schritt des Deployments müssen der Deployment-Monolith und die Microservices gemeinsam getestet werden. Diesen Schritt muss jede Änderung des Monolithen und aller Microservices durchlaufen. Dadurch ist ein Flaschenhals entstanden. Das Team »Benutzer« arbeitet gemeinsam unter anderem mit dem Team »Bestellprozess« am Deployment-Monolithen. Diese Teams müssen sich trotz Microservices immer noch eng abstimmen. Daher hat das Team »Bestellprozess« einen eigenen Microservice umgesetzt, der einen Teil des Bestellprozesses umfasst. Änderungen in diesem Teil des Systems sind im Vergleich zum Deployment-Monolithen nicht nur wegen der jüngeren Code-Basis schneller umgesetzt, sondern auch weil die Koordination mit den anderen Teams entfällt.
Aufstellung der Teams
Voraussetzung für die unabhängige Arbeit an Features ist die Aufstellung der Teams nach Fachlichkeiten wie Produktsuche, Benutzer oder Bestellprozess. Wenn stattdessen die Teams nach technischen Merkmalen wie UI, Middle Tier oder Datenbank aufgestellt sind, muss für jedes Feature jedes Team beteiligt werden. Schließlich wird ein Feature meistens Änderungen in UI, Middle Tier und Datenbank umfassen. Um Koordination zwischen den Teams zu minimieren, ist eine Aufstellung der Teams nach Fachlichkeiten auf jeden Fall sinnvoll. Microservices unterstützen die Unabhängigkeit durch eine technische Unabhängigkeit der einzelnen Services. Deswegen müssen Teams sich auch viel weniger bezüglich Basistechnologien und grundlegenden technischen Entwürfen koordinieren.
Die Tests müssen ebenfalls modularisiert werden. Jeder Test sollte einem einzigen Microservice zugeschlagen werden. Dann reicht es, wenn der Test bei Änderungen an diesem Microservice ausgeführt wird. Außerdem kann es sein, dass der Test dann als Unit-Test umgesetzt werden kann statt als Integrationstest. So wird die Testphase, in der alle Microservices und der Monolith gemeinsam getestet werden, zunehmend kürzer. Das verringert das Problem der Koordination für die letzte Testphase.
Die Migration hin zu einer Microservices-Lösung hat einige Performance-Probleme erzeugt und auch Probleme bei Netzwerkausfällen. Diese Schwierigkeiten konnten allerdings mit der Zeit gelöst werden.
Dank der neuen Architektur können Änderungen wesentlich schneller deployt werden. Eine Änderung kann von einem Team innerhalb von 30 Minuten in Produktion gebracht werden. Der Deployment-Monolith hingegen wird wegen der teilweise noch nicht automatisierten Tests nur wöchentlich deployt.
Neben der höheren Geschwindigkeit sind die Deployments der Microservices auch sonst wesentlich angenehmer: Es ist viel weniger Koordinierung notwendig. Fehler können schneller gefunden und behoben werden, weil die Entwickler noch sehr genau wissen, woran sie gearbeitet haben – schließlich ist das nur 30 Minuten her.
Letztendlich wurde das Ziel erreicht: Die Entwickler können viel mehr Änderungen an dem E-Commerce-Shop vornehmen. Das ist möglich, weil die Teams ihre Arbeit wesentlich weniger koordinieren müssen und weil die Deployments der Services unabhängig voneinander erfolgen können.
Die Möglichkeit, unterschiedliche Technologien zu nutzen, haben die Teams sparsam genutzt: Der bisher verwendete Technologie-Stack war ausreichend. Zusätzliche Komplexität durch den Einsatz von unterschiedlichen Technologien wollten die Teams vermeiden. Allerdings wurde für die Produktsuche die lange überfällige Suchmaschine eingeführt. Diese Änderung konnte von dem Team, das für die Produktsuche verantwortlich ist, alleine durchgeführt werden. Zuvor war die Einführung dieser neuen Technologie lange Zeit unterbunden worden, weil das Risiko als zu groß eingeschätzt wurde. Und einige Teams haben mittlerweile neue Versionen der Bibliotheken aus dem Technologie-Stack in Produktion, weil sie auf die Bug Fixes angewiesen waren. Dazu war keine Koordination über die Teams notwendig.
Das Ablösen eines Monolithen durch das Einführen von Microservices ist schon fast ein Klassiker für die Einführung von Microservices. Monolithen weiterzuentwickeln und mit neuen Features zu versehen, ist aufwendig. Die Komplexität und damit die Probleme des Monolithen nehmen über die Zeit zu. Eine vollständige Ablösung durch eine andere Software ist schwierig, weil dann die Software komplett ersetzt werden muss – und das ist risikoreich.
Schnelle und unabhängige Entwicklung neuer Features
Gerade bei Unternehmen wie der Raffzahn Online Commerce GmbH sind die schnelle Entwicklung neuer Features und die parallele Arbeit an mehreren Features überlebenswichtig. Nur so können Kunden gewonnen und davon abgehalten werden, zu anderen Anbietern zu wechseln. Das Versprechen, mehr Features schneller zu entwickeln, machen Microservices für viele Einsatzkontexte sehr attraktiv.
Einfluss auf die Organisation
Dieses Beispiel verdeutlicht auch den Einfluss von Microservices auf die Organisation. Die Teams arbeiten jeweils auf eigenen Microservices. Weil die Microservices unabhängig voneinander entwickelt und deployt werden können, ist die Arbeit der Teams voneinander entkoppelt. Dazu darf aber ein Microservice nicht von mehreren Teams parallel weiterentwickelt werden. Zu der Microservices-Architektur gehört eine Organisation der Teams entsprechend den Microservices: Jedes Team ist für einen oder mehrere Microservices zuständig, die eine isolierte Funktionalität umsetzen. Diese Beziehung zwischen Organisation und Architektur ist gerade bei Microservices sehr wichtig. Die Teams kümmern sich um alle Belange des Microservice von der Anforderungsaufnahme bis hin zur Betriebsüberwachung. Selbstverständlich können gerade für den Betrieb gemeinsame Infrastrukturdienste für Logging oder Monitoring genutzt werden.
Und schließlich: Wenn das Ziel ein einfaches und schnelles Deployment in Produktion ist, reicht die Umstellung der Architektur auf Microservices nicht aus. Die gesamte Continuous-Delivery-Pipeline muss auf Hindernisse untersucht und diese müssen ausgeräumt werden. Das zeigen im Beispiel die Tests: Ein gemeinsames Testen sollte auf das notwendige Minimum beschränkt sein. Jede Änderung muss einzeln einen Integrationstest mit den anderen Microservices durchlaufen, aber der darf nicht besonders lange dauern.