Verteilte autonome Microservices mit Event-Driven Architektur
Viele Organisationen nutzen Microservices, doch der Einsatz erschwert die synchronisierte Kommunikation zunehmend. Dass alle Systeme jederzeit verfügbar und alle Änderungen zu jedem Zeitpunkt konsistent sind, lässt sich nicht mehr sicherstellen. Und die enge Verknüpfung der Dienste durch die synchrone Kommunikation kann dazu führen, dass der Ausfall eines Dienstes gleichzeitig den Ausfall einer Reihe weiterer Dienste zur Folge hat. Typische Resilience Patterns wie Circuit-Breaker, Retries und Service Meshes erhöhen wiederum die Komplexität des Gesamtsystems und lösen das eigentliche Problem nur teilweise.
In diesem Artikel möchte ich verschiedene Arten der Architektur und asynchronen Kommunikation erläutern, und dabei die Vor- und Nachteile sowie die Herausforderungen jeder Art diskutieren.
Request-Driven Architektur
Die klassische Microservice-Architektur, oft auch als Request-Driven- oder Request/Response-Modell bezeichnet, basiert auf direkten Anfragen zwischen Services, meist über RESTful APIs. In diesem Modell sendet ein Dienst eine Anfrage an einen anderen und wartet auf die Antwort, bevor er fortfahren kann. Diese Methode ist leicht verständlich, da sie einem einfachen Frage-Antwort-Schema folgt, das dem menschlichen Dialog ähnelt: Ein Dienst fragt nach Informationen oder bittet um eine Handlung, ein anderer antwortet.
Diese direkte Form der Kommunikation ermöglicht eine strukturierte und sequentielle Abarbeitung von Geschäftsprozessen, was die Entwicklung und das Debugging vereinfacht. Sie führt aber auch zu einer engen Kopplung zwischen den Services. Das bedeutet, dass die Services stark voneinander abhängig sind: Fällt ein Service aus oder verzögert sich, kann dies direkte Auswirkungen auf die Performance und Verfügbarkeit des Gesamtsystems haben. Ein weiteres Problem ist die Skalierbarkeit, da die Komplexität der Verwaltung und Überwachung exponentiell mit der Anzahl der Anfragen und Dienste steigt.
Darüber hinaus müssen bei diesem Ansatz bei Änderungen an der Schnittstelle (API) häufig sowohl der anfragende als auch der antwortende Dienst aktualisiert werden, was den Wartungsaufwand erhöht. Darüber hinaus kann es bei Ausfällen zu Kettenreaktionen kommen, bei denen der Ausfall eines einzelnen Dienstes eine Lawine von Problemen bei anderen Diensten auslöst. Dieses Modell setzt eine hohe Verfügbarkeit und Zuverlässigkeit jedes einzelnen Microservices voraus, was in der Praxis schwer zu erreichen ist, insbesondere in komplexen Systemen mit vielen Services.
Event-Driven Architektur
Das ereignisgesteuerte Modell ist eine Architekturstrategie, die darauf abzielt, die Interaktion zwischen Microservices zu vereinfachen und zu verbessern, indem eine lose Kopplung und asynchrone Kommunikation gefördert werden. Man kann sich das wie ein großes Netzwerk vorstellen, in dem jeder Knoten (Service) unabhängig agiert und nur auf bestimmte Signale oder “Ereignisse” reagiert, die durch das System fließen.
Im Mittelpunkt dieses Systems steht das Publish-Subscribe-Modell: Ein Dienst (der Produzent) veröffentlicht ein Ereignis, z. B. die Aktualisierung eines Datensatzes, ohne zu wissen oder sich darum zu kümmern, wer dieses Ereignis erhält. Andere Services (die Konsumenten), die an diesem spezifischen Ereignis interessiert sind, haben sich im Voraus abonniert, um darüber informiert zu werden und können dann entsprechend reagieren, sei es durch Aktualisierung von Daten, Auslösen weiterer Prozesse oder anderer Aktionen.
Diese Entkopplung ermöglicht es den Diensten, unabhängig voneinander zu arbeiten und zu skalieren. Fällt ein Service aus, so hat dies keinen direkten Einfluss auf die Funktionsfähigkeit anderer Services, solange die Ereignisnachrichten korrekt gehandhabt werden. Dies erhöht die Ausfallsicherheit und Verfügbarkeit des Gesamtsystems. Da die Dienste asynchron kommunizieren, können sie ihre Aufgaben fortsetzen, ohne auf eine sofortige Antwort warten zu müssen, was die Effizienz erhöht und Engpässe reduziert.
Ein weiterer Vorteil der ereignisgesteuerten Architektur ist die Skalierbarkeit. Da die Dienste nicht direkt voneinander abhängig sind, können sie unabhängig voneinander je nach Bedarf skaliert werden. Dies ermöglicht eine effizientere Ressourcennutzung und eine bessere Anpassung an die Lastverteilung.
Diese Flexibilität bringt jedoch auch Herausforderungen mit sich, insbesondere im Bereich des Zustandsmanagements und der Konsistenzsicherung über verteilte Transaktionen hinweg. Ohne einen zentralen Orchestrator kann es schwieriger sein, komplexe Geschäftsprozesse zu steuern und sicherzustellen, dass alle Teile des Systems konsistent bleiben. Trotz dieser Herausforderungen bietet die ereignisgesteuerte Architektur eine robuste Grundlage für die Entwicklung skalierbarer und robuster Microservice-Systeme, indem sie die Vorteile der Entkopplung und der asynchronen Kommunikation nutzt.
Event Notification
In ereignisgesteuerten Architekturen spielt das Muster der Event Notification eine zentrale Rolle bei der Kommunikation zwischen den Komponenten. Dabei werden Ereignisse verwendet, um lose gekoppelte Systemteile über wichtige Ereignisse zu informieren. Ein wesentlicher Aspekt dieses Musters ist, dass die Benachrichtigungsereignisse in der Regel einfach aufgebaut sind und nur grundlegende Informationen über das eingetretene Ereignis enthalten. Diese Einfachheit führt dazu, dass eine Versionierung der Ereignisnachrichten selten erforderlich ist und die Systemkomponenten konsistent gehalten werden können.
Ein kritischer Punkt, der zusätzliche Überlegungen erfordert, ist die Situation, in der ein Konsument zusätzliche Daten vom Produzenten benötigt, um ein Ereignis zu verarbeiten. Diese Abhängigkeit führt zu einer direkten Kopplung zwischen beiden, da der Konsument möglicherweise eine Anfrage an den Produzent senden muss, um die benötigten zusätzlichen Informationen zu erhalten. Dies hat zwei wesentliche Auswirkungen auf das Systemdesign:
1. Verfügbarkeit des Produzenten
Nach der Veröffentlichung eines Ereignisses muss der Produzent verfügbar sein, um mögliche Anfragen von Konsumenten zu bearbeiten. Dies widerspricht dem Ideal der losen Kopplung, da die Fähigkeit des Konsumenten, auf das Event zu reagieren, direkt von der Verfügbarkeit des Produzenten abhängt.
2. Performance und Skalierbarkeit
Die Notwendigkeit für den Konsumenten, zusätzliche Daten vom Produzenten anzufordern, kann die Gesamtperformance und Skalierbarkeit des Systems beeinträchtigen. Jede Anfrage verursacht zusätzlichen Netzwerkverkehr und kann bei hoher Last zu Engpässen führen. Außerdem erhöht sich die Latenz bei der Ereignisverarbeitung, da der Konsument auf die Antwort des Produzenten warten muss, bevor er das Ereignis vollständig verarbeiten kann.
Unter Berücksichtigung des CAP-Theorems wird deutlich, dass die Entscheidung, eine hohe Konsistenz innerhalb des Systems durch direkte Anfragen von Konsumenten an Produzenten zu gewährleisten, die Verfügbarkeit und Performance beeinträchtigen kann. Insbesondere in Szenarien, in denen die Notwendigkeit besteht, eine hohe Verfügbarkeit zu gewährleisten, können diese direkten Abhängigkeiten problematisch sein.
Eine mögliche Lösung könnte der Einsatz von Techniken wie Caching oder die Implementierung eines umfassenderen Ereignisanreicherungsprozesses vor der Veröffentlichung des Ereignisses sein. Dadurch könnten die benötigten Daten bereits in der Event Notification enthalten sein, was die Notwendigkeit direkter Anfragen vom Konsumenten an den Produzenten reduzieren würde. Dies würde helfen, die lose Kopplung beizubehalten, die Verfügbarkeit zu erhöhen und die Performance in verteilten Systemen zu verbessern.
Event Carried State Transfer
Event Carried State Transfer in ereignisgesteuerten Architekturen ist ein Schema, das darauf abzielt, die Notwendigkeit für Konsumenten zu eliminieren, zusätzliche Daten vom Produzenten anzufordern, nachdem ein Ereignis empfangen wurde. Dies wird erreicht, indem alle relevanten Daten, die ein Konsument benötigen könnte, bereits im Ereignis selbst enthalten sind. Dieses Schema fördert die Autonomie und Entkopplung zwischen den Komponenten eines Systems, indem es sicherstellt, dass die Konsumenten in der Lage sind, ihre Verarbeitungslogik unabhängig und ohne externe Abhängigkeiten auszuführen.
Autonomie
Da jedes Ereignis alle notwendigen Informationen mit sich führt, können die Konsumenten unabhängig von den Produzenten agieren. Dies reduziert die Abhängigkeiten zwischen den Diensten und verbessert die Fehlertoleranz des Systems.
Entkopplung
Produzenten und Konsumenten sind weniger stark gekoppelt, da Konsumenten nicht zum Produzenten zurückkehren müssen, um fehlende Informationen zu erhalten. Dies erleichtert die Entwicklung und Wartung von Systemkomponenten.
Effizienz
Die direkte Verfügbarkeit aller benötigten Daten im Ereignis verringert die Notwendigkeit zusätzlicher Netzwerkaufrufe, was die Gesamtleistung und Reaktionsfähigkeit des Systems verbessert.
Da sich die Struktur der in einem Ereignis übertragenen Daten im Laufe der Zeit ändern kann, müssen Ereignisse versioniert werden, um sicherzustellen, dass die Nutzer in der Lage sind, verschiedene Versionen der Daten zu verstehen und korrekt zu verarbeiten. Dies erhöht die Komplexität des Systemdesigns und erfordert eine sorgfältige Planung, um Kompatibilitätsprobleme zu vermeiden.
Im Zusammenhang mit dem CAP-Theorem stellt der Event-Carried State Transfer eine interessante Herausforderung dar. Während dieses Schema die Verfügbarkeit und die Partitionstoleranz verbessert, indem es die Notwendigkeit direkter Kommunikation zwischen Produzenten und Konsumenten reduziert, kann es eine Herausforderung für die Konsistenz darstellen.
Die im Ereignis übertragenen Daten können zum Zeitpunkt der Verarbeitung veraltet sein. Dies kann zu Inkonsistenzen führen, insbesondere in schnelllebigen Umgebungen, in denen Daten häufig aktualisiert werden.
Event-Carried State Transfer bietet eine leistungsfähige Methode zur Förderung von Autonomie und Entkopplung in ereignisgesteuerten Architekturen. Indem alle notwendigen Daten direkt in das Ereignis eingebettet werden, können Konsumenten unabhängig von den Produzenten arbeiten, was die Robustheit und Effizienz des Systems verbessert. Dieses Muster bringt jedoch auch Herausforderungen mit sich, insbesondere in Bezug auf die Versionierung von Ereignissen und die Verwaltung der Datenaktualität. Die Anwendung dieses Musters erfordert eine sorgfältige Abwägung der Vor- und Nachteile sowie eine sorgfältige Planung, um die Vorteile zu maximieren und die potenziellen Fallstricke zu minimieren. Im Zusammenhang mit dem CAP-Theorem ermöglicht Event-Carried State Transfer eine höhere Verfügbarkeit und Partitionstoleranz auf Kosten der sofortigen Konsistenz, während Eventual Consistency als Kompromisslösung dient, um dennoch ein konsistentes Systemverhalten über die Zeit zu gewährleisten.
Event Sourcing
Event Sourcing ist ein Architekturansatz, der darauf abzielt, alle Änderungen am Zustand einer Anwendung als eine Sequenz von Ereignissen (Events) zu speichern. Diese Ereignisse repräsentieren nicht nur die Änderungen, die am System vorgenommen wurden, sondern auch den Kontext, in dem sie stattfanden, einschließlich des Zeitpunkts und der Ursache. Auf diese Weise entsteht eine detaillierte Chronik aller Vorgänge innerhalb der Anwendung, die es ermöglicht, den Zustand des Systems zu jedem beliebigen Zeitpunkt in der Vergangenheit zu rekonstruieren.
Unveränderbarkeit der Ereignisse
Einmal gespeicherte Ereignisse werden nicht mehr verändert oder gelöscht. Dadurch wird sichergestellt, dass die Historie der Anwendungszustände immer nachvollziehbar und konsistent bleibt. Änderungen im System werden durch das Hinzufügen neuer Ereignisse dargestellt.
Zustandsrekonstruktion
Der aktuelle Zustand einer Anwendung kann durch sequentielle Abarbeitung aller gespeicherten Ereignisse von Anfang an rekonstruiert werden. Dadurch ist es möglich, beliebige Zustände in der Vergangenheit zu rekonstruieren und zu analysieren, wie sich bestimmte Entscheidungen auf den aktuellen Zustand ausgewirkt haben.
Audit- und Analysefähigkeit
Da alle Änderungen als Ereignisse aufgezeichnet werden, bietet Event Sourcing eine natürliche Audit-Trail-Funktion. Dies ist besonders wertvoll für Anwendungen, die strenge Compliance-Anforderungen erfüllen müssen oder bei denen eine lückenlose Rückverfolgbarkeit erforderlich ist.
Flexibilität bei der Datensicht
Event Sourcing ermöglicht die Erstellung verschiedener Sichten (Views) auf die gespeicherten Daten. Diese Ansichten können optimiert werden, um die Anforderungen verschiedener Anwendungsfälle zu erfüllen, ohne dass die grundlegende Ereignisspeicherung geändert werden muss. So können beispielsweise Zusammenfassungen, Aggregationen oder spezifische Projektionen des Datenzustands erstellt werden, um die Performance zu verbessern oder spezielle Analyseanforderungen zu unterstützen.
Zukunftssicherheit
Ein weiterer Vorteil von Event Sourcing ist die Möglichkeit, neue Sichten oder Verarbeitungslogiken auf bereits gesammelte Ereignisse anzuwenden. Dadurch können Anwendungen flexibel an neue Anforderungen angepasst werden, ohne dass die zugrunde liegende Datenstruktur verändert werden muss. Beispielsweise können neue Funktionen implementiert werden, die auf Datenanalysen oder Verhaltensmustern basieren, die zum Zeitpunkt der ursprünglichen Ereigniserfassung nicht vorgesehen waren.
Event Sourcing bietet viele Vorteile, bringt aber auch Herausforderungen mit sich. Die Verwaltung eines wachsenden Volumens von Ereignisdaten kann in Bezug auf Speicherbedarf und Verarbeitungsgeschwindigkeit anspruchsvoll sein. Darüber hinaus erfordert die Implementierung eines Event-Sourcing-Systems eine sorgfältige Planung, insbesondere im Hinblick auf die Ereignismodellierung und die Sicherstellung der Systemleistung.
Zusammenfassung
Die Event-Driven Architektur ist eine flexible und robuste Grundlage für die Entwicklung von verteilten, autonomen Microservices, da sie die Entkopplung und asynchrone Kommunikation zwischen Services unterstützt. Die Schlüssel zum Erfolg in einem solchen System sind das Verständnis der fachlichen Anforderungen, sowie die Kenntnis verschiedener Patterns und der damit verbundenen Kompromisse.
Die Implementierung einer ereignisgesteuerten Architektur erfordert eine sorgfältige Abwägung der Vor- und Nachteile sowie eine anpassungsfähige Planung, um das Potenzial voll auszuschöpfen und die Systemintegrität zu erhalten. Durch die Anwendung dieser Prinzipien können Entwickler leistungsfähige und zukunftssichere Microservice-Landschaften schaffen, die sowohl heutigen als auch zukünftigen Anforderungen gerecht werden.
Hinweise:
Interessieren Sie sich für Serverless Architekturen, dann vereinbaren Sie mit Florian Lenz einen Termin. Er begleitet Sie gerne als strategischer Partner von der Beratung und Analyse über die Konzeption und Architektur bis in die operative Umsetzung.
Wenn Ihnen der Beitrag gefällt oder Sie darüber diskutieren wollen, teilen Sie ihn gerne in Ihrem Netzwerk. Und falls Sie sich für weitere Tipps aus der Praxis interessieren, dann testen Sie gerne unseren wöchentlichen Newsletter mit neuen Beiträgen, Downloads, Empfehlungen und aktuellem Wissen. Vielleicht wird er auch Ihr Lieblings-Newsletter!
Florian Lenz
Florian Lenz ist Gründer der neocentric GmbH, zertifizierter Microsoft Trainer und Redner auf Konferenzen. Er verfügt über viel Expertise im Bereich Azure, organisiert Meetups und betreibt einen YouTube-Kanal zu Azure Serverless. neocentric hat er mit dem Ziel gegründet, Unternehmen in ihrer Effizienz, Kostenreduktion und Wettbewerbsfähigkeit zu stärken. Seine Spezialisierung auf serverlose Lösungen ermöglichen es ihm, innovative Ideen in führende Produkte umzusetzen. Gerne macht er dies auf authentische, bodenständige und praktische Art.