Technisches

Microservices oder nicht? Dein Team hat sich bereits entschieden

10. Nov 2021

Lass uns das Thema der Microservices-Architektur ein wenig tangential angehen. Die meisten Diskussionen darüber drehen sich um technologische Aspekte: Welche Sprache man wählen sollte, wie man die meisten RESTful-Services erstellt, welches Service Mesh am leistungsfähigsten ist usw.

Bei VSHN haben wir jedoch schon vor langer Zeit herausgefunden, dass der wichtigste Erfolgsfaktor für Softwareprojekte die Menschen sind. Und die These dieses Artikels ist, dass die Wahl von Microservices als Architekturmuster mehr mit der Organisationsstruktur deines Unternehmens zu tun hat als mit den technologischen Zwängen und Funktionen des Endprodukts.

Oder anders ausgedrückt: Dein Team hat sich bereits für eine Architektur für ihre Software entschieden, auch wenn es sich dessen nicht ganz bewusst ist. Und siehe da: Microservices könnten das sein oder auch nicht.

Definition

Zunächst einmal müssen wir die Microservices-Architektur definieren. Was ist das?

„Microservices“ ist ein Architekturmuster, bei dem die Funktionalität des gesamten Systems in völlig unabhängige Komponenten zerlegt wird, die über das Netzwerk miteinander kommunizieren.

Das Gegenstück zur Microservices-Architektur ist der so genannte „Monolith“, der in den letzten 25 Jahren der häufigste Ansatz für Webapplikationen und -dienste war. In einem Monolithen sind alle Funktionen der Anwendung, von der Datenverwaltung bis zur Benutzeroberfläche, in einem einzigen Binary oder Paket enthalten.

Auf der gegenüberliegenden Seite der Strasse finden wir die Microservices-Architektur, bei der jeder Dienst für seine eigene Implementierung und Datenspeicherung verantwortlich ist.

Per Definition sind Microservices feingranular und haben einen einzigen Zweck. Sie weisen eine starke Kohäsion auf, d. h. die von ihnen eingekapselten Vorgänge sind in hohem Masse miteinander verbunden. Sie sind ein Beispiel für das „Single Responsibility Principle“. Sie werden auch separat bereitgestellt, mit deutlich abgegrenzten Kontexten, und sie erfordern DevOps-Ansätze für ihre Bereitstellung und Verwaltung, wie Automatisierung und CI/CD-Pipelines.

Sehr wichtig ist, dass die Microservices-Architektur eine „Share-Nothing-Architektur“ ist, bei der die einzelnen Dienste niemals gemeinsamen Code über Bibliotheken teilen, sondern die gesamte Interaktion und Kommunikation auf das sie verbindende Netzwerk beschränkt ist.

Und nicht zuletzt sollten Microservices (wie der Name schon sagt) so klein wie möglich sein, einen geringen Speicherbedarf haben und in Sekundenschnelle starten und stoppen können.

Angesichts all dieser Merkmale sind Microservices das mit Abstand komplexeste Architekturmuster, das je geschaffen wurde. Es ist schwer zu planen, kann die Komplexität von Projekten drastisch erhöhen und war für einige Teams erfahrungsgemäss nicht zu bewältigen.

Geschichte

Die Idee, dass sich „Komponenten gegenseitig Nachrichten schicken“, ist absolut nicht neu. Bereits 1966 prägte einer der grössten Informatiker aller Zeiten, Alan Kay, den Begriff „objektorientierte Programmierung“. Die Industrie hat seine ursprüngliche Definition, die wie folgt lautete, übernommen und verformt:

OOP bedeutet für mich nur Messaging, lokale Speicherung und Schutz und Verstecken von State-Process, und extreme Late-Binding aller Dinge.

Alan Kay, Quelle.

Dieser Text stammt aus dem Jahr 2003, der folgende aus dem Jahr 1998:

Die grosse Idee ist „Messaging“ – das ist es, worum es im Kern von Smalltalk/Squeak geht (…) Der Schlüssel zum Aufbau grossartiger und wachstumsfähiger Systeme liegt eher darin, zu entwerfen, wie die Module kommunizieren, als was ihre internen Eigenschaften und Verhaltensweisen sein sollten.

Alan Kay, Quelle.

Alan Kay entwickelte in den 1970er Jahren die Programmiersprache Smalltalk, die auf diesen Konzepten basiert. Und nach der Lektüre der obigen Texte wird klar, dass die Microservices-Architektur zu einem grossen Teil eine Umsetzung von Alan Kays Ideen von Messaging, Entkopplung und Abstraktion ist, die auf die Spitze getrieben wurde.

Um den heutigen Stand der Microservices zu erreichen, waren jedoch viele weitere Durchbrüche erforderlich. In den 2000er Jahren wurde mit dem Aufkommen von XML, dem SOAP-Protokoll und den damit zusammenhängenden Webdiensten der Begriff „serviceorientierte Architektur“ zu einem weit verbreiteten Grundnahrungsmittel in Architekturdiskussionen. Mit dem Aufkommen agiler Methoden wandte sich die Branche dem REST-Ansatz anstelle von SOAP zu. Im letzten Jahrzehnt ermöglichten das Aufkommen von DevOps und der Aufstieg der Containerisierung durch Docker und Kubernetes den Teams schliesslich die Bereitstellung von Tausenden von Containern als Microservice-Architektur, dank des gesamten Katalogs der Cloud-Native-Technologien.

Pro und Kontra

Wenn Microservice-Architekturen so komplex sind, warum sollten sie dann eingesetzt werden? Es stellt sich heraus, dass sie viele Vorteile bringen können:

  • Da jede Komponente vollständig von den anderen isoliert werden kann, können die Teams, sobald sie sich auf ihre Schnittstellen geeinigt haben, diese zu 100 % unabhängig von den anderen entwickeln, dokumentieren und gründlich testen. Auf diese Weise können die Teams parallel vorgehen und Funktionen implementieren, die zu 0 % miteinander kollidieren können.
  • Die Teams werden ausserdem ermutigt, die Programmiersprache zu wählen, die am besten zu der jeweiligen Aufgabe passt, die ihr Microservice erfüllen muss.
  • Da es sich per definitionem um „Mikro“-Dienste handelt, sind sie so konzipiert, dass sie schnell gestartet und wieder beendet werden können, so dass sie nur bei Bedarf eingreifen und das gesamte System effizienter und reaktionsfähiger machen.
  • Die Grösse von Microservices ermöglicht auch eine höhere Verfügbarkeit, da es möglich ist, viele von ihnen hinter einem Load Balancer zu haben; sollte eine Instanz eines Microservices ausfallen, kann sie schnell entlassen werden und eine neue an ihrer Stelle instanziiert werden, ohne dass die Verfügbarkeit verloren geht.
  • Systeme können schrittweise aktualisiert werden, wobei jedes Team Fehler behebt und Funktionen hinzufügt, ohne die anderen zu stören. Solange die Schnittstellen beachtet (und schliesslich versioniert) werden, gibt es keinen Grund, dass das System unter den Aktualisierungen leidet.

Es gibt jedoch viele Gründe, sich nicht für die Microservices-Architektur zu entscheiden; unter den wichtigsten sind:

  • Leistung: Ein mit Microservices aufgebautes System muss die Latenz zwischen diesen Diensten berücksichtigen; und in dieser Hinsicht sind monolithische Anwendungen schneller; ein Funktionsaufruf ist immer schneller als ein Netzwerkaufruf.
  • Reife des Teams: Microservices erfordern von den Teams ein gewisses Mass an Erfahrung und Fachwissen; bei Teams, die neu im Bereich Microservices sind, ist die Wahrscheinlichkeit eines Projektfehlschlags höher.
  • Kosten: Die Erstellung eines Microservices-Systems ist, wenn überhaupt, teurer, da jeder einzelne Dienst einen Overhead verursacht.
  • Machbarkeit: Manchmal ist es einfach nicht möglich, Microservices zu nutzen, zum Beispiel wenn es um Altsysteme geht.
  • Teamstruktur: Dies ist ein entscheidender Faktor, auf den wir später noch ausführlich eingehen werden.
  • Komplexität: Es ist nicht ungewöhnlich, dass Systeme aus Tausenden von gleichzeitigen Diensten bestehen, und dies führt zu Herausforderungen, auf die wir später noch eingehen werden.

Ich möchte nun auf die letzten beiden Punkte eingehen, die unserer Erfahrung nach die grössten Probleme bei Microservice-Implementierungen darstellen: Teamstruktur und die Wahrnehmung und Bewältigung von Komplexität.

Conway’s Law

Einer der entscheidenden Faktoren, der die Fähigkeit von Teams zur Implementierung von Microservices einschränkt, ist oft unsichtbar und wird übersehen: Ihre eigene Struktur. Auch dieses Phänomen ist nicht neu. Im Jahr 1968 schrieb Melvin A. Conway für die Zeitschrift Datamation einen Artikel mit dem Titel „How Do Committees Invent?“, in dem die folgende Idee hervorsticht:

Die Grundthese dieses Artikels ist, dass Organisationen, die Systeme entwerfen (…), gezwungen sind, Designs zu produzieren, die Kopien der Kommunikationsstrukturen dieser Organisationen sind.

Melvin Conway, Quelle.

Dafür gibt es umfangreiche Belege, sowohl anekdotische als auch empirische, die durch die Forschung belegt sind.

Die Konsequenz dieses Prinzips ist die folgende: Die Entscheidung zwischen einer monolithischen und einer Microservices-Architektur ist bereits im hierarchischen Diagramm einer jeden Organisation verankert.

Eine der Dienstleistungen, die wir bei VSHN anbieten, befasst sich genau mit diesem Thema. In unserem „DevOps-Enablement-Workshop“ bewerten wir den Grad der Agilität von Organisationen sowie das Ausmass und die Verbesserungen, die DevOps bringen könnte. Auf der Grundlage dieser Informationen führen wir ein Reverse-Engineering ihrer Struktur durch das Conway’sche Gesetz durch, um einen Ausgangspunkt für ihre digitale Transformation zu finden.

Komplex vs. Kompliziert

Ein weiterer wichtiger Punkt ist die Unterscheidung zwischen „komplex“ und „kompliziert“, da diese beiden Wörter in der Alltagssprache manchmal miteinander verwechselt werden können, und um die Sache noch schwieriger zu machen, kann das Wort „einfach“ als Antonym für beide verwendet werden.

„Komplex“ kommt aus dem Lateinischen complexus und bedeutet „aus ineinander verschlungenen Elementen bestehend“. Complexus ist wiederum von plectere („biegen, verflechten“) abgeleitet. Dieses Wort wird seit dem XVI. Jahrhundert verwendet, um etwas zu bezeichnen, das sich aus heterogenen Elementen zusammensetzt. Es hat dieselbe Wurzel (plectere) wie der medizinische Begriff „Plexus“, der „Geflecht“ bedeutet und seit dem 16. Jahrhundert als medizinischer Begriff für „Nerven- oder Blutgefässnetz“ verwendet wird.

(Quelle: Dictionnaire historique de la langue française von Alan Rey)

„Kompliziert“ hingegen hat einen ähnlichen Ursprung, aber eine andere Konstruktion: Es kommt vom lateinischen complicare, was wörtlich „zusammenfalten“ bedeutet. Im übertragenen Sinne wurde dies als Nähe zum Begriff der Peinlichkeit oder Unbeholfenheit verstanden. Das Wort setzt sich aus dem Wort plicare zusammen, das „falten“ bedeutet. Uhren, die gemeinhin als „Komplikationen“ bezeichnet werden (wie das Kaliber 89 von Patek Philippe, die Aeternitas Mega von Franck Muller und die „Référence 57260“ von Vacheron Constantin), sind per Definition komplizierte Maschinen.

Kurz gesagt, „komplex“ und „kompliziert“ stammen von leicht unterschiedlichen Wurzeln ab: Der lateinischen Wurzel plectere („verflechten“) für Ersteres und plicare („falten“) für Letzteres. Der Begriff „kompliziert“ vermittelt die Vorstellung eines Netzes von miteinander verflochtenen Objekten, deren Zustand und Verhalten sich durch die Interaktion mit anderen Objekten in diesem Netz ständig ändert. Das Wort kompliziert impliziert eine inhärente scheinbare „Unklarheit“ durch Faltung in sich selbst, die zu einem „sich entfaltenden“ Entdeckungsprozess einlädt.

Oder anders ausgedrückt: einzelne Microservices sollten nicht kompliziert sein, aber eine Microservice-Architektur ist per Definition komplex. Monolithen hingegen neigen dazu, mit der Zeit sehr kompliziert zu werden. Und natürlich sind beide nicht einfach.

Die Geschichte zeigt, dass Softwareentwickler ein leidenschaftliches Verhältnis zur Kompliziertheit haben; komplizierte Systeme sind grossartig, um auf Hacker News damit zu prahlen, während Maintainer auch privat über sie weinen.

Eine „Best Practice“ hat in diesem Zusammenhang eine und nur eine grundlegende Aufgabe: den Ingenieuren zu helfen, das Komplizierte in das Komplexe zu übersetzen. Die meisten softwarebezogenen Katastrophen werden durch eine einfache Tatsache verursacht: Aufgrund von Fristen, Organisation, Werkzeugen oder schlichtweg Unwissenheit neigen Softwareentwickler dazu, komplizierte statt komplexe Systeme zu bauen.

Dies ist ein weiterer Punkt, um den wir uns in unserem DevOps-Workshop kümmern, und zwar durch die Bewertung der aktuellen Ressourcen (nicht nur Quellcode, sondern auch aktuelle Datenbankschemata, Sicherheitsanforderungen, Netzwerktopologien, Bereitstellungsverfahren und -rhythmen usw.).

Migrieren oder umschreiben? Gleichgewicht

Die Kompliziertheit von Monolithen an sich ist nicht problematisch; sie führt zu eng gebundenen Systemen, die in der Regel sehr schnell sind, da, wie gesagt, ein Funktionsaufruf schneller ist als ein Netzaufruf. Schliesslich haben wir in der Vergangenheit sehr erfolgreich Monolithen gebaut. Aber die Erfahrung zeigt, dass sie in Bezug auf Verfügbarkeit und Skalierbarkeit Probleme bereiten. Microservices stellen einen diametral entgegengesetzten Ansatz dar, der eher auf Komplexität als auf Kompliziertheit beruht, der aber diese Probleme löst.

Es besteht also ein Spannungsverhältnis zwischen Komplexität und Kompliziertheit auf der einen und organisatorischen Zwängen auf der anderen Seite. Mit anderen Worten, es besteht ein Spannungsverhältnis zwischen monolithischen und Microservices-Systemen auf der einen Seite und mehr oder weniger hierarchischen Strukturen auf der anderen Seite. Ein Gleichgewicht zwischen diesen Kräften zu erreichen, ist also die technische Herausforderung, der sich Softwarearchitekten heutzutage stellen müssen.

Viele Teams stehen heute vor der Aufgabe, ihre Monolithen auf Microservice-basierte Architekturen zu migrieren, entweder auf Wunsch des Managements oder auf Grund von Kunden- oder Lieferantenanforderungen. Architekten können zum Glück einige Techniken anwenden, um ein Gleichgewicht zu finden:

  1. Beginne den Migrationspfad im Bewusstsein, dass oft nicht die gesamte Anwendung auf Microservices umgestellt werden muss. Einige Teile können und sollten monolithisch bleiben, und insbesondere bewährte ältere Systeme, auch wenn sie in COBOL oder älteren Technologien geschrieben wurden, können immer noch einen Wert darstellen und eine sehr wichtige Rolle für den Erfolg des Übergangs spielen.
  2. Identifiziere die Komponenten richtig, so dass sie im isolierten Zustand weder nur funktions-, noch nur daten-, noch nur anforderungsgesteuert sind, sondern von diesen drei Faktoren (Funktionalität, Daten und Anforderung) gleichzeitig gesteuert werden. Achte auf das Organigramm und verwende dieses als Grundlage für die Dekomposition in Microservices.
  3. Denke daran, dass die Netzwerkbandbreite nicht unbegrenzt ist. Einige Schnittstellen sollten „klobig“ sein, während andere „gesprächig“ sein sollten. Plane von Anfang an Latenzprobleme ein.
  4. Reduziere die Kommunikation zwischen den Dienststellen so weit wie möglich, was auf verschiedene Weise geschehen kann:
    1. Konsolidierung der Dienste
    2. Konsolidierung von Datendomänen (Kombination von Datenbankschemata oder Verwendung gemeinsamer Caches)
    3. Verwendung von Technologien wie GraphQL zur Verringerung der Netzwerkbandbreite
    4. Verwendung von Messaging-Warteschlangen, wie RabbitMQ.
  5. Einführung von Microservice-freundlichen Technologien wie Docker-Container, Kubernetes, Knative oder Red Hat OpenShift und Quarkus.
  6. Implementiere eine automatisierte Teststrategie für jeden einzelnen Microservice.
  7. Standardisiere Technologie-Stacks rund um Container und Kubernetes und schaffe eine gemeinsame Basis für ein echtes Microservice-Ökosystem in Unternehmen.
  8. Automatisiere die Arbeit so weit wie möglich, da sich der Aufwand für die Automatisierung (DevOps, CI/CD) über viele Dienste hinweg amortisieren kann und sich somit langfristig als Nettoinvestition erweist.

Wie bereits erwähnt, helfen wir Organisationen regelmässig bei ihrer digitalen Transformation in Richtung Microservices, Kubernetes, OpenShift, DevOps, CI/CD, GitLab und DevOps im Allgemeinen, um ihre Teams mit den Werkzeugen zu unterstützen, die sie in der Zukunft benötigen werden. In Anlehnung an das Konzept der Team-Topologien von Henny Portman kann VSHN sowohl als „Enabling Team“ (DevOps-Workshops, Beratung) als auch als „Platform Team“ (Kubernetes/OpenShift) unterstützen, um Microservices zu entwickeln und Stabilität und Sicherheit zu gewährleisten.

Schlussfolgerung

Microservice-Architekturen sind nicht nur ein Hype, sondern bringen auch grosse Vorteile mit sich, können aber auch eine grosse Herausforderung für Software-Teams darstellen.

Der beste Weg, diese Herausforderungen zu bewältigen, besteht darin, das Conway’sche Gesetz umzukehren und zunächst die menschliche Organisation deiner Teams zu analysieren. Mach sie unabhängig, agil und frei in der Wahl der besten Werkzeuge für ihre Arbeit. Ermutige sie, untereinander die Schnittstellen ihrer jeweiligen Komponenten auszuhandeln.

Lass uns komplexe, nicht komplizierte Systeme schaffen und betreiben. Wir können uns nicht von der Komplexität lösen; das ist unsere Aufgabe als Ingenieure. Aber wir können den komplizierten Teil loswerden.

Abschliessend möchte ich meinen ehemaligen Kollegen und lebenslangen Freund Adam Jones, einen unabhängigen IT-Berater aus Genf, zitieren: Um mit der Microservice-Architektur Erfolg zu haben, musst du Struktur in deine Aktivitäten einbetten und sie aus der Hierarchie entfernen. Es geht nicht darum, die Struktur verschwinden zu lassen, sondern sie dorthin zu verlagern, wo sie am meisten Nutzen bringt.

Adrian Kosmaczewski

Adrian Kosmaczewski ist bei VSHN für den Bereich Developer Relations zuständig. Er ist seit 1996 Software-Entwickler, Trainer und veröffentlichter Autor. Adrian hat einen Master in Informationstechnologie von der Universität Liverpool.

Kontaktiere uns

Unser Expertenteam steht für dich bereit. Im Notfall auch 24/7.

Kontakt