Microservices: Starke Medizin – aber gegen was? Oder: Wo Sie Microservices einsetzen sollten und wo nicht!
Microservices sind in aller Munde. Es scheint – mal wieder – bloß noch eine Frage der Zeit zu sein, bis sie die Softwareentwicklung revolutioniert und dabei gleich die wichtigsten Probleme aus der Welt geräumt haben. Also der übliche Hype? Nicht ganz. In diesem Fall ist die Gemengelage noch unübersichtlicher als gewohnt. Nicht nur, dass es wenig Übereinstimmung darüber gibt, was der Begriff überhaupt beschreibt, es kommt noch hinzu, dass fast immer völlig verschiedene Aufgabenfelder miteinander vermischt werden.
Unglücklicherweise geraten dabei bewährte Methoden und Erfahrungen völlig aus dem Blick. Der Artikel versucht, durch Bezüge zu etablierten Techniken etwas Ordnung zu stiften und damit die Orientierung zu erleichtern. Denn eines ist ja bereits erwiesen: Richtig und an den richtigen Stellen angewandt, sind Microservices hoch effizient.
Abgrenzung: Was ist ein Microservice?
Um vernünftig über ein Thema diskutieren zu können, braucht es ein Minimum an begrifflicher Klarheit. Während diese bei etablierten Anwendungsgebieten gemeinhin gegeben ist, scheint beim Stichwort Microservices noch vieles im Fluss. Das liegt nicht zuletzt an der Entstehungsgeschichte. Prinzipiell gibt es zwei Wege zu neuen Konzepten:
- Ausgehend von einem generellen Problem wird eine abstrakte Lösungsidee gesucht und, so man sie findet, in die Praxis umgesetzt – Theorie zuerst.
- Aus der Lösung eines konkreten praktischen Problems wird ein allgemeineres Vorgehen extrahiert und als Konzept präsentiert – Praxis zuerst.
Im Internet-Zeitalter gewinnt offensichtlich der zweite Weg – man könnte ihn auch "Probieren geht über Studieren" nennen – immer mehr an Bedeutung. Bei aller Sympathie für den starken Praxisbezug ist allerdings nicht zu übersehen, dass auf diesem Weg Gefahren lauern. Die Größte besteht darin, vorhandenes Wissen zu ignorieren und möglicherweise das Rad neu zu erfinden, gern auch schlechter. Das muss nicht so sein, ist jedoch oft zu beobachten. Ein anderes Defizit der zweiten Methode ergibt sich dagegen zwangsläufig daraus, dass vom Konkreten auf das Allgemeine geschlossen wird. Für die Frage, welche Eigenschaften vernachlässigt werden können und welche nicht, gibt es keine Regeln. Selbst Erfahrung hilft nur wenig, weil jeweils der Standpunkt und die Ziele des Betrachters und damit seine Wertung dessen, was wichtig ist, eine entscheidende Rolle spielen. Je vielgestaltiger das ursprüngliche Phänomen ist, desto mehr Betrachtungsmöglichkeiten ergeben sich.
Genau darin liegt das Dilemma jeder Diskussion über Microservices. Es gibt eine kleine Anzahl beeindruckend erfolgreicher Implementierungen, aber es ist immer noch umstritten, welche Prinzipien das tragende Gerüst der Erfolge bilden. Entsprechend vielfältig sind die angebotenen Definitionen. So findet sich beispielsweise "Microservices sind SOA (Serviceorientierte Architektur), aber richtig gemacht" oder "Applications that fit in your head" oder "Einheiten, die von einem kleinen Team komplett – sowohl fachlich als auch technologisch – beherrscht werden können" [1]. Weit verbreitet ist zudem die Beschreibung von Adrian Cockcroft: "Loosely coupled service oriented architecture with bounded contexts" [2].
Allen Definitionen gemeinsam ist, dass sie explizit oder implizit Voraussetzungen einschließen, die nicht nur die unmittelbare Softwareentwicklung, sondern den gesamten Zyklus von der Anforderungsanalyse bis zum Betrieb umfassen. Genannt sei nur das Stichwort Automated Continuous Deployment, das allein schon eine erhebliche technische und organisatorische Herausforderung benennt. Da das dahinter stehende Konzept nicht auf Microservices beschränkt ist, wird es hier nicht weiter vertieft.
Das Kernkonzept von Microservices ist die Modularisierung.
Der Sinn dieser Ausführungen besteht darin, zu zeigen, dass es derzeit nicht sinnvoll ist, bei der Erkundung von Grenzen für den Einsatz von Microservices von einer Definition auszugehen. Es gibt einfach zu viele Faktoren, deren Wichtigkeit und Zusammenspiel erst noch durch praktische Erprobung erforscht werden müssen – dies erinnert durchaus an die Situation bei der Erprobung eines neuen Arzneiwirkstoffs. Aber das heißt nicht, dass man dieser neuen Technologie nun völlig ratlos gegenüber stände. Schließlich handelt es sich bei den Microservices nicht um etwas voraussetzungslos Neues, sondern um die geschickte Kombination etablierter Techniken. Die wichtigen Charakteristika dieser Techniken verschwinden nicht und können damit – quasi von innen heraus – ein Gerüst für die Beurteilung liefern. In Analogie zur mathematischen Terminologie kann man sagen, dass auf dieser Basis "notwendige Bedingungen" für den sinnvollen Einsatz von Microservices formulierbar sind.
Das Kernkonzept, das in allen Definitionsversuchen für Microservices – wenn auch unter verschiedenen Bezeichnungen – auftaucht, ist die Modularisierung. Es geht immer darum, statt eines großen, unhandlichen Monolithen, kleine, flexiblere Services zu schaffen. Der einzige erkennbare Unterschied zu dem, was üblicherweise unter Modularisierung verstanden wird, ist die Konsequenz, mit der dieser Ansatz verfolgt wird. Man findet sogar Stimmen, die Microservices vor allem deshalb einsetzen wollen, um die konsequente Trennung zwischen den Modulen zu erzwingen. Da das Konzept nicht neu ist, gibt es ein umfangreiches Wissen.
Ein anderes, ebenfalls nicht neues und unbestritten essentielles Konzept lässt sich mit dem Begriff der verteilten Verarbeitung umschreiben. Auch dieses Gebiet wird seit rund vierzig Jahren intensiv bearbeitet und bietet einen Fundus an verwertbaren Erkenntnissen. Es wäre fahrlässig, diese Erfahrungen nicht zu berücksichtigen. Leider fehlt in der IT bisher eine angemessene Erfahrungs- und Fehlerkultur. Entsprechend schwer ist es, instruktive Berichte zu finden. Trotzdem lassen sich aus den vorliegenden Erkenntnissen wichtige Schlussfolgerungen ziehen. Einige davon werden im Folgenden betrachtet.
Microservices: Abgegrenzter Kontext (Bounded Context)
Der abgegrenzte Kontext ist ein wichtiger Begriff in der Welt der Microservices. Er stammt aus dem Domain-Driven Design (DDD) [3]. Große, schwer oder nicht mehr überschaubare Domänenmodelle werden in abgegrenzte Kontexte mit definierten Schnittstellen, letztlich Module, zerlegt. Es ist nicht notwendig, dass alle Kontexte auf den gleichen Konzepten oder Modellen beruhen. Praktisch handelt es sich also um die Ausweitung des Modularisierungskonzepts auf den fachlichen Anwendungsbereich.
Conways Gesetz und Microservices
Mel Conway hat die nach ihm benannte These bereits 1967 aufgestellt: "Organizations which design systems … are constrained to produce designs which are copies of the communication structures of these organizations." [4]
Nach seiner eigenen Aussage ist sie nicht auf IT-Systeme beschränkt, in diesem Bereich aber besonders populär geworden. Insbesondere im Zusammenhang mit Microservices wird immer wieder darauf verwiesen. Dabei wird jedoch das Ausmaß der sich ergebenden Konsequenzen oft unterschätzt, weil man sich zu stark auf die IT und die unmittelbar betroffenen Fachbereiche beschränkt. Wenn Services wirklich als weitgehend unabhängige Einheiten entwickelt und deployt werden sollen, dann muss die gesamte Geschäftsstruktur auf lose gekoppelte Einheiten ausgerichtet sein. Das erfordert vielerorts eine weitreichende Umstellung der Managementstrukturen. Außerdem muss die Geschäftsstrategie anerkennen, "dass Microservices kein Ansatz sind, um die Kosten der Softwareentwicklung zu minimieren. Es gehe vielmehr darum, die Reaktionszeiten – Stichwort Time-to-Market – sowie die Qualität der Systeme deutlich zu verbessern." [1]
Die Schlussfolgerung daraus lautet: Microservices sind ein übergreifendes strategisches IT-Konzept, das aus der Geschäftsführung heraus getrieben werden muss. Das ist vor allem für bestehende Unternehmen eine enorme Herausforderung, weil es bisherigen Zielsetzungen teilweise zuwider läuft. In der Vergangenheit sind die aus der technischen Entwicklung, d. h. der Vernetzung, resultierenden besseren Kommunikationsmöglichkeiten überwiegend für die Kostensenkung durch Zentralisierung genutzt worden. Lose Kopplung von relativ unabhängigen Einheiten heißt demgegenüber Dezentralisation von Verantwortung und bedingt in gewissem Umfang Redundanzen.
Aus rein technischer Sicht mögen Microservices zwar ebenfalls interessant sein, verursachen aber vor allem höhere Kosten. Ein geschäftlicher Nutzen kann sich über längere Zeit aus der schnellen und unabhängigen Produktivsetzung neuer umsatzgenerierender Features ergeben. Ohne entsprechende Geschäftsorganisation muss man allerdings befürchten, dass diese Technologie allein nicht verhindern kann, dass letztlich doch wieder ein – zumindest logisch – monolithisches System entsteht.
Microservices: Die Zerlegungsillusion
Die Überschrift ist bewusst provokativ gewählt. Über die Vorteile der Modularisierung braucht man nicht zu sprechen. Sie sind so bekannt und überzeugend, dass über die ebenfalls damit verbundenen Probleme und Nachteile nur selten diskutiert wird. Das liegt unter anderem auch daran, dass die Methode, Komplexität durch Zerlegung beherrschbar zu machen, elementar ist. Jeder hat sie unzählige Male angewandt, wobei vor allem die erfolgreichen Versuche die Erinnerung bestimmen. Leider ist es aber so, dass die Grenzen unzureichend beachtet werden. Das kann man immer wieder erleben, wenn eine schwierige Frage zerlegt und auf Arbeitsgruppen verteilt wird. Alle haben das Gefühl, damit der Lösung einen großen Schritt näher gekommen zu sein. Oft ist das eine trügerische Illusion.
Komplexität lässt sich nicht "wegmodularisieren".
Um jedem Irrtum vorzubeugen: Es geht nicht darum, das Zerlegen als Methode zu diskreditieren. Man sollte sich nur bewusst werden, dass jede Zerlegung darauf beruht, dass von der ursprünglichen Konstellation so lange abstrahiert wird, bis sich hinreichend überschaubare Teile ergeben. Auf dieser Abstraktionsebene kann dann mental agiert werden. Wie gut das funktioniert, hängt entscheidend davon ab, ob die richtigen Eigenschaften isoliert wurden. Was wichtig ist, hängt wiederum von der konkreten Problemstellung ab.
Eine Zerlegung der Realität in Blöcke (abgegrenzte Kontexte, Module, Objekte) setzt also immer eine entsprechende Vereinfachung voraus. Je komplexer das Anwendungsgebiet ist, desto stärker muss abstrahiert werden, d. h. desto mehr Aspekte werden ausgeblendet. Dadurch wird jedoch gleichzeitig der Bereich kleiner, für den das Modell nützliche Schlüsse zulässt. In der Wissenschaft hilft man sich dadurch, dass man für den gleichen Gegenstand unterschiedliche Modelle oder Theorien entwickelt und deren Ergebnisse zu kombinieren versucht. Bei der Softwareentwicklung ist ein solcher Ansatz nur sehr eingeschränkt – z. B. durch aspektorientierte Programmierung – möglich, weil nur eine einzige Sicht in Form von Code implementiert werden kann.
Komplexität lässt sich nicht "wegmodularisieren". Die auf den ersten Blick vielleicht überraschende Schlussfolgerung lautet daher, dass die strukturelle Zerlegung in abgegrenzte Kontexte vor allem dann effektiv ist, wenn die Anwendungsdomäne das ohne zu starke Vereinfachungen zulässt. Das bedeutet, es existieren bereits entsprechende funktionale Einheiten mit überschaubaren Schnittstellen untereinander oder sie können einfach geschaffen werden (Was man dabei nicht unterschätzen sollte, ist, dass es häufig neben der "offiziellen" auch noch eine "inoffizielle" Kommunikationsstruktur gibt. Meist wird das erst entdeckt, wenn nach der Einführung neuer Prozesse plötzlich Dinge nicht mehr funktionieren oder viel länger dauern.) Damit ist der Bezug zum vorhergehenden Abschnitt hergestellt: Ohne entsprechende Kommunikationsstruktur im Unternehmen ist es schwer bis unmöglich, eine wirklich modulare IT-Lösung zu etablieren. Das ist ein großes Problem für gewachsene Unternehmen, von denen einige erhebliches Lehrgeld zahlen mussten, weil sie diese Erfordernisse ignoriert haben.
Auf längere Sicht begrenzt die Zerlegung überdies die Möglichkeiten der Weiterentwicklung. Wenn die Zerlegungsstruktur erhalten bleiben soll, können in jedem Kontext nur die Merkmale berücksichtigt werden, von denen nicht abstrahiert wurde. Das wird für einige Zeit ausreichend sein, aber wie lange ist kaum vorhersehbar. Nach einer Phase der Konsolidierung und Optimierung entsteht in der Regel das Bedürfnis, weitere Aspekte einzubeziehen. Am eindrucksvollsten ist diese Tatsache an den Wissenschaften zu sehen, wo immer wieder zwischen scheinbar völlig getrennten Fächern (=abgegrenzten Kontexten) neue Forschungsgebiete entstehen – mit entsprechenden Folgen für die Organisationsstruktur: Es gibt unzählige Berichte über die Schwierigkeiten und Paradoxien bei der Beantragung von Forschungsmitteln oder bei der Begutachtung von Publikationen in Folge der unklaren Zuordnung.
Modularisierung und Microservices
Modularisierung ist ein rekursiv anwendbares Konzept. Hier steht vor allem die Ebene im Fokus, auf der Microservices entstehen sollen. Der Großteil der Aussagen gilt aber für jedes Niveau.
Nach den prinzipiellen Problemen der Zerlegung in Module sollen jetzt die eher praktisch-technische Fragen erörtert werden. Wie bereits erwähnt, findet man kaum Berichte über die Umsetzung in größeren Projekten. Eine löbliche Ausnahme stellt ein Beitrag [5] dar, in dem die Erfahrungen aus einer Reihe von Modularisierungsprojekten in der Industrie zusammengetragen wurden.
Voraussetzungen zur Modularisierung von Microservices
Modularisierung ist kein Selbstzweck. Sie bringt nicht nur Vorteile, sondern verursacht gleichzeitig Aufwand und Kosten. Deshalb müssen die damit verfolgten Ziele von Anfang an klar definiert sein. Wie bei allen Entscheidungen, die die Zukunft betreffen, ist das Risiko, etwas falsch eingeschätzt zu haben, nicht vermeidbar. Unklare oder zu allgemeine Zielvorgaben sind jedoch noch riskanter.
Wenn eine Zerlegung in abgegrenzte Kontexte vorliegt, muss diese gründlich überprüft werden. Zu den in [5] identifizierten wichtigen Fehlerquellen gehören nämlich übersehene Abhängigkeiten und ungeprüfte Annahmen. Letztere sind besonders heimtückisch. Sie entstehen, wenn Behauptungen so oft wiederholt werden, dass sie schließlich von allen als Fakten akzeptiert werden, obwohl sie gar nicht allgemein zutreffen.
Diese Kontrolle sollte besonders kritisch erfolgen, wenn ein vorhandenes System wegen zu großer Komplexität ersetzt werden soll. Wie oben beschrieben, spiegeln IT-Systeme die Kommunikationsstruktur wider, sodass mangelhafte Struktur in den meisten Fällen nicht nur auf nachträgliche Änderungen und schlechte Implementierung zurückgeht, sondern oft die Widerspieglung (eventuell unnötig) komplexer Geschäftsabläufe ist. In einem derartigen Szenario sind von der IT keine Wunder zu erwarten und mehr als eine graduelle Verbesserung ist nicht möglich.
Schnittstellen von Microservices
Nachdem die Aufgabe der grundsätzlichen Zerlegung gelöst ist, besteht die nächste Herausforderung im Definieren geeigneter Schnittstellen. Dabei muss das richtige Maß zwischen Allgemeinheit und Detailliertheit gefunden werden. Durch die Schnittstelle wird eine Fachsprache für die Kommunikation mit dem Modul bzw. abgegrenzten Kontext definiert. Wie gut eine solche Definition ist, hat Auswirkungen auf das Gesamtsystem:
- Verständlichkeit und Konsistenz verringern die Fehlerwahrscheinlichkeit bei der Anwendung.
- Genügende Allgemeinheit unterstützt die Evolution der Systems.
- Zu große Allgemeinheit kann unnötigen Aufwand verursachen (bekanntes Beispiel dafür sind Parameter, die dann immer mit dem gleichen festen Wert belegt werden).
- Übermäßige Detailliertheit erhöht den Aufwand beim Aufrufer und die Wahrscheinlichkeit für fehlerhafte Aufrufe.
- Ungünstige Datenstrukturen können die Effizienz zur Laufzeit verringern.
Es ist unwahrscheinlich, dass gleich beim ersten Versuch ein gutes Ergebnis gelingt. Deshalb ist es wichtig, zunächst in einer Umgebung zu entwickeln, in der Schnittstellen unkompliziert verändert werden können. Da der Teufel häufig im Detail steckt, dürfen entsprechende Pilotimplementierungen nicht zu oberflächlich sein.
Solange handhabbare Mittel fehlen, um eine Schnittstelle formal vollständig zu spezifizieren, ist es unabdingbar, ihre Beschreibung von Anfang an durch möglichst umfassende Testfälle zu komplettieren.
Unabhängigkeit der Microservices
Lose gekoppelte Module ohne gemeinsame Datenhaltung erfordern in vielen Fällen ganz andere Strategien der Datenverarbeitung. In einem vollständig modularisierten System darf es keine globale "Single Source of Truth" geben. Trotzdem soll sich die Anwendung als Ganzes konsistent verhalten. Das lässt sich nur durch Redundanzen in der Datenhaltung und der Verarbeitung verwirklichen. Auch hier kommt wieder die Kommunikationsstruktur ins Spiel. Wenn in einem bestehenden System alles über eine zentrale Datenbank gekoppelt ist, muss diese enge Kopplung der Geschäftsprozesse erst aufgelöst werden. In der Regel wird sich das nicht ohne Änderungen für die betroffenen Fachbereiche erreichen lassen.Grundsätzlich sollte das fast immer möglich sein – schließlich waren Unternehmen schon lange und auch weltumspannend (z. B. die Fuggers oder die Hanse) tätig, bevor es zentrale Datenbanken gab. Eine Ausnahme ist möglicherweise der Hochfrequenzhandel an den elektronischen Börsen.
Außerdem sind auf der technischen Ebene zusätzliche Funktionen notwendig. Wie erfahren beispielsweise die einzelnen Module voneinander? Im Fehlerfall muss durch sogenannte Circuit-Breaker verhindert werden, dass es zu Kaskadeneffekten kommt. Der dynamische Austausch sowie das Ab- und Zuschalten von Modulen muss gewährleistet werden.
Der beschriebene Aufwand muss durch die gewonnene Flexibilität gerechtfertigt werden.
Das heißt, es müssen hohe Anforderungen an die rasche Weiterentwicklung der IT-Lösung oder die Anpassbarkeit einzelner Funktionen bestehen, die mit einer monolithischen Softwarestruktur nicht abgedeckt werden können.
Wartbarkeit von Microservices
Auf den ersten Blick verbessern Microservices dank ihres geringen Umfangs und der klar abgegrenzten Funktionalität ohne Frage die Wartbarkeit. Das ist jedoch an einige Voraussetzungen gebunden, die nicht in jeder Umgebung dauerhaft gegeben sind.
Selbst wenn es gelungen ist, von der Projekt- auf eine Produktsicht [6] zu wechseln, wird es sich oft nicht vermeiden lassen, dass, bezogen auf einzelne Services, unterschiedliche Anforderungen hinsichtlich des Tempos der Weiterentwicklung entstehen. Für relativ stabile, nur sporadisch modifizierte Teile kommt es dadurch doch wieder zu projekthaftem Arbeiten mit den bekannten Problemen, verschärft dadurch, dass explizite Integrationstests eigentlich nicht existieren. Bei Bank- oder Medizinanwendungen beispielsweise ist es aber nicht tolerierbar, Implementationen freizugeben, die möglicherweise nicht ausreichend fehlerfrei sind.
Ein anderes Risiko ergibt sich aus den unvermeidbar unvollständigen Schnittstellendefinitionen. Im Laufe der Zeit steigt die Wahrscheinlichkeit, dass ursprüngliche implizite Annahmen beispielsweise durch Fluktuation in den Teams verblassen oder durch andere Annahmen ersetzt werden. Da sich dessen niemand bewusst ist, kann das nur schwer erkannt werden und die Folgen zeigen sich vielleicht erst mit großer zeitlicher Verzögerung.
Falls schließlich für die Entwicklung die jeweils passendsten Werkzeuge verwendet werden, also unterschiedliche Tools, Paradigmen und Sprachen, so heißt das für die Wartung, dass diese Vielfalt an Know-how dauerhaft erhalten und weiterentwickelt werden muss. Das hat Konsequenzen für die Mindestgröße von Anwendungen und Organisationen, für welche dieser Ansatz wirtschaftlich vertretbar ist. Dabei ist insbesondere auch der oben erwähnte Aspekt zu bedenken, dass unter Umständen für bestimmte Funktionsbereiche zeitweise kein Entwicklungsbedarf besteht.
Microservices und verteilte Prozesse
Herausforderungen verteilter Prozesse
Microservice-Architekturen sind per Definition verteilte Systeme. Da diese seit vielen Jahren untersucht werden, gibt es übertragbare Erfahrungen. Die Wichtigste, die auch durch nützliche Hilfsmittel (z. B. Container) nicht entwertet wird, lautet: Ein verteiltes System ist schwieriger und aufwändiger zu verwalten. Skalierbarkeit und Flexibilität haben ihren Preis: "At the end of the day, managing a single system is easier than a distributed one. … however, microservices are not free; the trade-off for having flexibility and scalability is having to manage a complicated system." [6]
Die größte Schwierigkeit erwächst jedoch daraus, dass in verteilten Systemen – im Unterschied zu monolithischen Anwendungen – die verschiedenen Technologien intensiv interagieren. Ein Methodenaufruf ist Bestandteil der Programmiersprache – die Nutzung eines REST-Services umfasst einen ganzen Technologiestack. Das erfordert in höherem Grad querschnittliches Wissen von der Programmierung bis zu Netzwerkprotokollen, welches, da bislang nur selten nachgefragt, erst entwickelt werden muss. Gute Netzwerkadministratoren waren beispielsweise auch ohne Microservices schon begehrt und knapp. Jetzt besteht die Gefahr, dass durch die leicht verfügbaren Cloud-Entwicklungsumgebungen diese Frage vernachlässigt wird. Aber jedem, der ernsthaft auf verteilte Systeme setzt, sollte klar sein, dass – früher oder später – unerwartete Probleme und Fehler auftauchen oder die Anforderungen so stark wachsen, dass die vorkonfigurierten Systeme nicht mehr ausreichen. Ganz abgesehen davon, dass es natürlich höchst nützlich ist, entsprechende Kompetenz bereits bei der Konzeption verfügbar zu haben.
Ganz grundsätzlich gilt festzuhalten, dass verteilte Anwendungen so viele neue Aspekte haben und bekannten Aspekten andere Gewichte verleihen, dass es sehr leichtsinnig wäre, größere Projekte ohne experimentelle Vorbereitung anzugehen. Die notwendigen Erfahrungen sind nur selten in ausreichendem Grad vorhanden und nicht durch theoretische Kenntnisse zu ersetzen. Die Gefahr ist groß, dass Wichtiges erst im Verlauf des Projekts gelernt wird. Das aber ist extrem kostspielig, weil das Redesign von verteilten Anwendungen deutlich aufwändiger und schwieriger ist als das von monolithischen.
Verwaltung verteilter Prozesse
Für die Verwaltung, d. h. das Verteilen, Starten, Stoppen, Monitoren usw. von verteilten Prozessen, gibt es Frameworks und andere Hilfsmittel. Allerdings ist vieles noch im Fluss. Das ist für Pilotversuche kein Problem, kann sich aber als ernsthaftes Hindernis herausstellen, wenn benötigte Funktionen noch nicht stabil verfügbar sind.
Neben diesen grundlegenden technischen Funktionen, müssen die Verwaltungsprozesse auf die geschäftlichen Erfordernisse abgestimmt werden. Dazu gehört zunächst, die Identifikation relevanter Betriebskenngrößen. Auf deren Basis können dann Kriterien definiert werden, die es beispielsweise ermöglichen, zwischen Problemen, die rein technisch zu lösen sind und solchen, die Managemententscheidungen erfordern, zu differenzieren.
Eine zusätzliche Aufgabe ergibt sich, wenn – wie in Microservice-Strukturen üblich – die Elemente der Struktur dynamisch konfiguriert werden. Dabei muss sichergestellt werden, dass jede Komponente die benötigten Informationen über den aktuellen Stand der Gesamtstruktur erhält und dass alle erforderlichen Servicefunktionen mit ausreichender Kapazität verfügbar sind. Praktisch entsteht dadurch eine zweite Ebene der Anwendung, die ebenso gewartet und überwacht werden muss wie die einzelnen Programme. Es ist ein ernst zu nehmender Einwand, dass Microservices einen Teil der Komplexität aus den Komponenten in die Verbindungsstruktur verlagern, wo diese schwerer zu erkennen und zu steuern ist.
Schließlich stellt die Gewährleistung der im folgenden Abschnitt betrachteten Sicherheitsaspekte erhebliche Anforderungen an die Verwaltung.
Sicherheit verteilter Prozesse
Verteilte Prozesse bieten viele Angriffspunkte. Einen Monolithen kann man mittels Gateway relativ einfach absichern. Bei Prozessen, die über ein (offenes) Netz kommunizieren, muss jeder Knoten, jeder Service und jede Verbindung einzeln gesichert werden. Das ist keine einmalige Aufgabe. Vielmehr erfordert es unter anderem kontinuierliche Aktivitäten zur Überwachung von
- Gültigkeit der Zertifikate für geschützte Verbindungen,
- Sicherheitsupdates für die einzelnen Knoten-Betriebssysteme,
- Sicherheitspatches für verwendete Software und
- individuellen Zugriffsrechten.
Ein Teil dieser Aufgaben, z. B. das Patchen der Systemprogramme, wird in Cloud-Anwendungen durch den Anbieter der Infrastruktur übernommen. Anwendungsspezifische Bibliotheken müssen in jedem Fall aber selbst auf einem aktuellen Stand gehalten werden.
Darüber hinaus sollte bei einer verteilten Anwendung das Thema Sicherheit von Anfang an und umfassender betrachtet werden. Während in einem monolithischen Programm mögliche Aufrufstrukturen im Code gewissermaßen "fest verdrahtet" sind und damit statisch (a priori) überprüft werden können, ist die Kommunikationsstruktur zwischen verteilten Prozessen dynamisch. Ganz gleich, ob vorsätzlich oder irrtümlich, es ist prinzipiell immer möglich, dass Daten an einen ursprünglich nicht vorgesehenen Prozess gesendet werden. Für Anwendungen, die Daten unterschiedlicher Mandanten verarbeiten, ist die Gewährleistung der erforderlichen sicheren Trennung damit keine Funktion, die sich nachträglich einfach ergänzen ließe. Unabhängig davon ist jeder Kommunikationsendpunkt im Netz eine Schnittstelle der Anwendung zur Außenwelt und muss dementsprechend abgesichert werden. Die diesbezüglichen Anforderungen gehören deshalb zwingend zur Schnittstellendefinition.
Es ist im Allgemeinen keine gute Idee, solche Sicherheitsaspekte an die Netzwerkverwaltung auszulagern, etwa durch das Aufsetzen wechselseitig zertifizierter Direktverbindungen. Erstens sind solche Strukturen unübersichtlich, aufwändig zu betreuen und damit fehleranfällig. Zweitens geht ein Teil der angestrebten Flexibilität verloren, wenn ein zusätzlicher Serviceaufruf unter Umständen erst die Umkonfiguration des Netzwerks erfordert. Und letztlich fällt diese Variante ohnehin immer dann aus, wenn die möglichen Service-Konsumenten nicht vollständig bekannt sind oder ihre Menge zu groß ist.
Microservices: Verfahren und Geschäftsprozesse
Viele aktuell verwendete Verfahren sind auf eine konsistente Datenhaltung und bisweilen auch auf sequentielle Verarbeitung ausgelegt. Ohne gründliche Überarbeitung der Prozessabläufe wird man in der Regel durch das Verteilen von Anwendungen auf mehrere Knoten keine Vorteile erhalten. Es ist vielmehr zu erwarten, dass durch die zusätzliche Kommunikation die Gesamtleistung eher sinkt und die Verwaltungskosten steigen. Verfahren für eine verteilte Verarbeitung aufzubereiten ist eine anspruchsvolle Aufgabe. Man darf nicht vergessen, dass das Betreiben einer verteilten Anwendung Kosten verursacht, die durch die gewonnenen Vorteile wie Skalierbarkeit, Flexibilität usw. aufgewogen werden müssen. Daher wird es in vielen Fällen sinnvoll sein, zunächst über die Anpassung der Geschäftsprozesse nachzudenken. Nur wenn diese hinreichend parallelisierbar und skalierbar sind, ist ein so grundsätzlicher Wechsel der Implementierungsstrategie sinnvoll.
Ein anderer Aspekt, der ebenfalls bereits beim fachlichen Design beachtet werden muss, wird gemeinhin mit den Begriffen Resilience oder (nicht ganz deckungsgleich) Fehlertoleranz beschrieben. Verteilte Systeme bieten nicht nur mehr Angriffspunkte, sie sind auch viel anfälliger für Ausfälle einzelner Komponenten, das gilt insbesondere für die Kommunikation. Um trotzdem die gewünschte hohe Verfügbarkeit zu erreichen, sind spezielle Techniken nötig, die bei lokalen Fehlern die Funktionsfähigkeit der Gesamtanwendung möglichst vollständig erhalten. Wenn solche Überlegungen bereits in den Entwurf der fachlichen Prozesse Eingang finden, wird die spätere Umsetzung wesentlich erleichtert und zuweilen überhaupt erst möglich. Denn es ist im Allgemeinen nicht trivial zu definieren, wie mit zeitweise fehlerhaften Komponenten umgegangen werden soll. Bei zustandslosen Prozessen ist das weniger schwierig, aber wenn ein Prozess beispielsweise bereits Daten akkumuliert hat, vorübergehend ausfällt und später dann wieder verfügbar wird, kann der Umgang mit diesen Informationen eine knifflige Angelegenheit sein. Auf rein IT-technischer Ebene lassen sich derartige Fragen nicht beantworten.
Fazit
Microservices sind ein interessantes Konzept, dass auf den ersten Blick die Lösung vieler altbekannter Probleme der Softwareentwicklung verspricht. Die genauere Untersuchung zeigt jedoch, dass im Inneren dieser Technik viele ebenso altbekannte Hürden lauern. Die neue Verpackung lässt sie nicht verschwinden. Hinter der scheinbar einfachen Struktur verbergen sich sowohl konzeptionelle als auch technische Herausforderungen.
Der Aufwand, eine nachhaltige auf Microservices basierende IT-Architektur aufzubauen, darf auf keinen Fall unterschätzt werden. Die Technologie ist nicht darauf ausgerichtet, Kosten zu sparen. In der Regel wird der Einsatz nicht erfolgversprechend sein, wenn die Kommunikations- bzw. Geschäftsstrukturen nicht dazu passen. Die wichtigsten Vorteile, die man bei erfolgreicher Umsetzung erhalten kann, sind:
- Eine flexible IT-Struktur, deren einzelne Komponenten unabhängig und schnell weiterentwickelt werden können.
- Eine äußerst flexibel skalierbare IT-Struktur, die in Sekunden an stark wechselnde Belastungen angepasst werden kann.
Wenn diese beiden Anforderungen nicht bestehen, sollte sehr genau überdacht werden, ob Microservices wirklich die angemessene Lösung sind. Eine saubere Architektur mit konsequenter Modularisierung und auf Services beruhenden Schnittstellen ist oft die wirtschaftlichere Lösung. Gut gemacht, bietet sie gleichzeitig die Basis, um bei späterem echten Bedarf daraus Microservices zu bauen.
- L. Röwekamp: Microservices: (noch) keine einheitliche Definition
- A. Cockcroft: The State of the Art in Microservices
- M Fowler: BoundedContext
- M. Conway: Conway's Law
- J. Knodel, M. Naab, B. Weitzel: Modularity - Often Desired, but Rarely Achieved. Softwaretechnik-Trends. 2015, Bd. 35, 2, S. 37-38
- J. Davis: Why do MicroServices projects fail to Deliver?
- C. Posta: Microservices for Java Developers. Sebastopopl CA : O'Reilly Media, 2016. 978-1-491-96308-1.