Ereignisgesteuerter Architekturstil
Eine ereignisgesteuerte Architektur besteht aus Ereignisproduzenten, die einen Datenstrom von Ereignissen, Ereigniskonsumenten generieren, die auf diese Ereignisse lauschen, und Ereigniskanäle, die Ereignisse von Produzenten an Verbraucher übertragen.
Ereignisse werden nahezu in Echtzeit übermittelt, sodass Consumer unmittelbar nach dem Auftreten des Ereignisses reagieren können. Die Hersteller entkoppeln sich von den Verbrauchern: Ein Hersteller weiß nicht, welche Verbraucher zuhören. Consumer sind auch voneinander entkoppelt, und jeder Consumer sieht alle Ereignisse. Dieser Prozess unterscheidet sich von einem Muster konkurrierender Verbraucher , bei dem Verbraucher Nachrichten aus einer Warteschlange abrufen und eine Nachricht nur einmal verarbeitet wird, vorausgesetzt, es gibt keine Fehler. In einigen Systemen, z. B. Azure Internet of Things (IoT), müssen Ereignisse mit hohen Volumes aufgenommen werden.
Eine ereignisgesteuerte Architektur kann ein Veröffentlichungsabonnentmodell oder ein Ereignisstreammodell verwenden.
Pub/sub: Die Veröffentlichungs-Abonnieren-Messaging-Infrastruktur verfolgt Abonnements. Wenn ein Ereignis veröffentlicht wird, sendet die Infrastruktur das Ereignis an jeden Abonnenten. Ein Ereignis kann nicht wiedergegeben werden, nachdem es empfangen wurde, und neue Abonnenten sehen das Ereignis nicht.
Ereignisstreaming: Ereignisse werden in ein Protokoll geschrieben. Ereignisse werden in einer Partition streng sortiert und sind dauerhaft. Clients abonnieren den Datenstrom nicht. Stattdessen kann ein Client aus einem beliebigen Teil des Datenstroms lesen. Der Kunde ist dafür verantwortlich, seine Position im Stream voranzutreiben. Dies bedeutet, dass ein Client jederzeit beitreten kann und Ereignisse wiedergeben kann.
Auf Consumerseite gibt es einige gängige Variationen:
Einfache Ereignisverarbeitung: Ein Ereignis löst sofort eine Aktion im Consumer aus. Sie können z. B. Azure-Funktionen mit einem Azure Service Bus-Trigger verwenden, sodass eine Funktion immer dann ausgeführt wird, wenn eine Nachricht in einem Service Bus-Thema veröffentlicht wird.
Grundlegende Ereigniskorrelation: Ein Verbraucher verarbeitet einige einzelne Geschäftsereignisse, korreliert sie anhand eines Bezeichners und speichert Informationen aus früheren Ereignissen zur Verwendung bei der Verarbeitung späterer Ereignisse. Bibliotheken wie NServiceBus und MassTransit unterstützen dieses Muster.
Komplexe Ereignisverarbeitung: Ein Verbraucher verwendet eine Technologie wie Azure Stream Analytics, um eine Reihe von Ereignissen zu analysieren und Muster in den Ereignisdaten zu identifizieren. Sie können beispielsweise Lesewerte von einem eingebetteten Gerät über ein Zeitfenster aggregieren und eine Benachrichtigung generieren, wenn der gleitende Durchschnitt einen bestimmten Schwellenwert überschreitet.
Ereignisdatenstromverarbeitung: Verwenden Sie eine Datenstreamingplattform, z. B. Azure IoT Hub oder Apache Kafka, als Pipeline zum Aufnehmen von Ereignissen und feeden sie in Streamprozessoren. Die Datenstromprozessoren verarbeiten oder transformieren den Datenstrom. Möglicherweise gibt es mehrere Datenstromprozessoren für verschiedene Subsysteme der Anwendung. Dieser Ansatz eignet sich gut für IoT-Workloads.
Die Quelle der Ereignisse kann außerhalb des Systems sein, z. B. physische Geräte in einer IoT-Lösung. In diesem Fall muss das System in der Lage sein, die Daten auf dem Volume und dem Durchsatz aufzunehmen, den die Datenquelle benötigt.
Es gibt zwei primäre Ansätze zum Strukturieren von Ereignisnutzlasten. Wenn Sie die Kontrolle über Ihre Ereigniskonsumenten haben, können Sie die Nutzlaststruktur für jeden Verbraucher festlegen. Mit dieser Strategie können Sie Ansätze nach Bedarf innerhalb einer einzigen Workload kombinieren.
Alle erforderlichen Attribute in die Nutzlast einschließen: Verwenden Sie diesen Ansatz, wenn Verbraucher alle verfügbaren Informationen erhalten sollen, ohne eine externe Datenquelle abfragen zu müssen. Es kann jedoch zu Datenkonsistenzproblemen führen, da mehrere Datensatzsysteme, insbesondere nach Updates, auftreten. Vertragsverwaltung und Versionsverwaltung können auch komplex werden.
Nur Schlüssel in die Nutzlast einschließen: Bei diesem Ansatz rufen Verbraucher die erforderlichen Attribute, z. B. einen Primärschlüssel, ab, um die verbleibenden Daten aus einer Datenquelle unabhängig abzurufen. Diese Methode bietet eine bessere Datenkonsistenz, da sie über ein einzelnes Datensatzsystem verfügt. Dies kann jedoch schlechter als der erste Ansatz sein, da Verbraucher die Datenquelle häufig abfragen müssen. Sie haben weniger Bedenken hinsichtlich Kopplung, Bandbreite, Vertragsverwaltung oder Versionsverwaltung, da kleinere Ereignisse und einfachere Verträge die Komplexität verringern.
Im vorherigen Diagramm wird jeder Verbrauchertyp als einzelnes Feld angezeigt. Um zu vermeiden, dass der Verbraucher zu einem einzigen Fehlerpunkt im System wird, ist es typisch, mehrere Instanzen eines Verbrauchers zu haben. Mehrere Instanzen können auch erforderlich sein, um das Volume und die Häufigkeit von Ereignissen zu behandeln. Ein einzelner Consumer kann Ereignisse in mehreren Threads verarbeiten. Dieses Setup kann Herausforderungen auslösen, wenn Ereignisse in der Reihenfolge verarbeitet werden müssen oder genau einmal semantische Semantik erfordern. Weitere Informationen finden Sie unter Minimieren der Koordination.
Zahlreiche ereignisgesteuerte Architekturen weisen zwei primäre Topologien auf:
Brokertopologie: Komponenten übertragen Vorkommen als Ereignisse in das gesamte System. Andere Komponenten reagieren entweder auf das Ereignis oder ignorieren das Ereignis. Diese Topologie ist nützlich, wenn der Ereignisverarbeitungsablauf relativ einfach ist. Es gibt keine zentrale Koordination oder Orchestrierung, sodass diese Topologie dynamisch sein kann. Diese Topologie ist hochgradig entkoppelt, was eine bessere Skalierbarkeit, Reaktionsfähigkeit und Fehlertoleranz von Komponenten ermöglicht. Es gibt keine Komponente, die den Status einer mehrstufigen Geschäftstransaktion besitzt oder über diesen informiert ist, und die Aktionen werden asynchron ausgeführt. Anschließend sind verteilte Transaktionen riskant, da es keine systemeigene Möglichkeit gibt, neu gestartet oder wiedergegeben zu werden. Sie müssen fehlerbehandlungs- und manuelle Interventionsstrategien sorgfältig berücksichtigen, da diese Topologie eine Quelle für Dateninkonsistenzen sein kann.
Mediatortopologie: Diese Topologie behebt einige der Mängel der Brokertopologie. Es gibt einen Ereignisvermittler, der den Ablauf von Ereignissen verwaltet und steuert. Der Ereignismediator verwaltet den Status und die Funktionen für die Fehlerbehandlung und den Neustart. Im Gegensatz zur Brokertopologie übertragen Komponenten in dieser Topologie Vorkommen als Befehle und nur auf bestimmte Kanäle. Diese Kanäle sind in der Regel Nachrichtenwarteschlangen. Es wird erwartet, dass Verbraucher diese Befehle verarbeiten. Diese Topologie bietet mehr Kontrolle, bessere verteilte Fehlerbehandlung und potenziell bessere Datenkonsistenz. Diese Topologie führt zu einer erhöhten Kopplung zwischen Komponenten, und der Ereignisvermittler kann zu einem Engpass oder zu einer Zuverlässigkeitssorge werden.
Einsatzmöglichkeiten für diese Architektur
Sie sollten diese Architektur in folgenden Fällen verwenden:
- Mehrere Subsysteme, die die gleichen Ereignisse verarbeiten müssen
- Die Echtzeitverarbeitung mit minimalem Zeitabstand ist erforderlich.
- Komplexe Ereignisverarbeitung, z. B. Musterabgleich oder Aggregation im Zeitfenster, ist erforderlich.
- Hohe Datenmenge und hohe Datengeschwindigkeit sind erforderlich, wie z. B. IoT.
Vorteile
Die Vorteile dieser Architektur sind:
- Producer und Consumer sind entkoppelt.
- Keine Punkt-zu-Punkt-Integrationen. Neue Consumer lassen sich problemlos zum System hinzufügen.
- Verbraucher können sofort auf Ereignisse reagieren, sobald sie auftreten.
- Hochskalierbar, elastisch und verteilt.
- Subsysteme weisen unabhängige Perspektiven des Ereignisstroms auf.
Herausforderungen
Garantierte Übermittlung.
In manchen Systemen – insbesondere in IoT-Szenarien – ist es von entscheidender Bedeutung, sicherstellen zu können, dass Ereignisse übermittelt werden.
Verarbeitung der Ereignisse in einer bestimmten Reihenfolge oder genau einmal.
Für Resilienz und Skalierbarkeit wird jeder Verbrauchertyp in der Regel in mehreren Instanzen ausgeführt. Dieser Prozess kann eine Herausforderung erstellen, wenn die Ereignisse in der Reihenfolge eines Consumertyps verarbeitet werden müssen oder wenn idempotente Nachrichtenverarbeitungslogik nicht implementiert ist.
Nachrichtenkoordination über Dienste hinweg.
Geschäftsprozesse verfügen häufig über mehrere Dienste, die Nachrichten veröffentlichen und abonnieren, um ein konsistentes Ergebnis über einen gesamten Workload hinweg zu erzielen. Sie können Workflowmuster wie das Choreographiemuster und Saga Orchestration verwenden, um Nachrichtenflüsse zuverlässig über verschiedene Dienste hinweg zu verwalten.
Fehlerbehandlung.
Ereignisgesteuerte Architektur verwendet hauptsächlich asynchrone Kommunikation. Eine Herausforderung bei der asynchronen Kommunikation ist die Fehlerbehandlung. Eine Möglichkeit, dieses Problem zu beheben, besteht darin, einen separaten Fehlerhandlerprozessor zu verwenden. Wenn der Ereignisanwender einen Fehler aufweist, sendet es sofort und asynchron das fehlerhafte Ereignis an den Fehlerhandlerprozessor und wechselt fort. Der Fehlerhandlerprozessor versucht, den Fehler zu beheben und sendet das Ereignis an den ursprünglichen Erfassungskanal zurück. Wenn der Fehlerhandlerprozessor jedoch fehlschlägt, kann es das fehlerhafte Ereignis zur weiteren Überprüfung an einen Administrator senden. Wenn Sie einen Fehlerhandlerprozessor verwenden, werden fehlerhafte Ereignisse aus der Sequenz verarbeitet, wenn sie erneut gesendet werden.
Datenverlust.
Eine weitere Herausforderung bei asynchroner Kommunikation ist Datenverlust. Wenn eine der Komponenten abstürzt, bevor das Ereignis erfolgreich verarbeitet und an die nächste Komponente übergeben wird, wird das Ereignis verworfen und nie zum endgültigen Ziel. Um die Wahrscheinlichkeit eines Datenverlusts zu minimieren, speichern Sie Transitereignisse, und entfernen oder deaktivieren Sie die Ereignisse nur, wenn die nächste Komponente den Empfang des Ereignisses bestätigt. Diese Features werden als Client-Bestätigungsmodus und letzte Teilnehmerunterstützung bezeichnet.
Implementierung eines herkömmlichen Anforderungsantwortmusters.
Manchmal erfordert der Ereignisproduzent eine sofortige Antwort des Ereignisanwenders, z. B. das Abrufen der Kundenberechtigung, bevor er mit einer Bestellung fortsetzt. In einer ereignisgesteuerten Architektur kann die synchrone Kommunikation mithilfe von Anforderungsantwortnachrichten erreicht werden.
Dieses Muster wird in der Regel mit zwei Warteschlangen implementiert: einer Anforderungswarteschlange und einer Antwortwarteschlange. Der Ereignisproduzent sendet eine asynchrone Anforderung an eine Anforderungswarteschlange, hält andere Vorgänge für diese Aufgabe an und wartet auf eine Antwort in der Antwortwarteschlange. Dieser Ansatz wandelt dieses Muster effektiv in einen synchronen Prozess um. Ereigniskonsumenten verarbeiten dann die Anforderung und senden die Antwort zurück über eine Antwortwarteschlange. Bei diesem Ansatz wird in der Regel eine Sitzungs-ID für die Nachverfolgung verwendet, sodass der Ereignisproduzent weiß, welche Nachricht in der Antwortwarteschlange mit der spezifischen Anforderung verknüpft ist. Die ursprüngliche Anforderung kann auch den Namen der Antwortwarteschlange angeben, potenziell kurzlebig, in einem Antwort-to-Header oder einem anderen sich gegenseitig vereinbarten benutzerdefinierten Attribut.
Wartung der entsprechenden Anzahl von Ereignissen.
Durch die Generierung einer übermäßigen Anzahl fein abgestimmter Ereignisse kann das System gesättigt und überwältigt werden, wodurch es schwierig ist, den Gesamtfluss von Ereignissen effektiv zu analysieren. Dieses Problem wird verschärft, wenn Änderungen zurückgesetzt werden müssen. Umgekehrt können übermäßig konsolidierende Ereignisse auch Probleme verursachen, was zu unnötigen Verarbeitungen und Antworten von Ereigniskonsumenten führt.
Um das richtige Gleichgewicht zu erzielen, berücksichtigen Sie die Folgen von Ereignissen und ob Verbraucher die Ereignisnutzlasten überprüfen müssen, um ihre Antworten zu bestimmen. Wenn Sie beispielsweise über eine Kompatibilitätsprüfungskomponente verfügen, reicht es möglicherweise aus, nur zwei Arten von Ereignissen zu veröffentlichen: konform und nicht konform. Dieser Ansatz trägt dazu bei, sicherzustellen, dass nur relevante Verbraucher jedes Ereignis verarbeiten, was unnötige Verarbeitung verhindert.
Weitere Überlegungen
Die Menge der Daten, die in einem Ereignis enthalten sein soll, kann ein wichtiger Aspekt sein, der sowohl die Leistung als auch die Kosten betrifft. Sie können den Verarbeitungscode vereinfachen und zusätzliche Nachschlagevorgänge beseitigen, indem Sie alle relevanten Informationen platzieren, die für die Verarbeitung direkt im Ereignis erforderlich sind. Wenn Sie nur eine minimale Menge an Informationen zu einem Ereignis hinzufügen, z. B. ein paar Bezeichner, reduzieren Sie die Transportzeit und die Kosten. Dieser Ansatz erfordert jedoch, dass der Verarbeitungscode alle benötigten zusätzlichen Informationen abruft. Weitere Informationen finden Sie unter "Platzieren Ihrer Ereignisse auf einer Diät".
Eine Anforderung ist nur für die Anforderungsbehandlungskomponente sichtbar. Ereignisse sind jedoch häufig für mehrere Komponenten in einer Workload sichtbar, auch wenn diese Komponenten nicht oder nicht dazu gedacht sind, sie zu nutzen. Achten Sie darauf, welche Informationen Sie in Ereignisse einbeziehen, um mit einer "Annahme von Sicherheitsverletzungen" zu arbeiten, um unbeabsichtigte Informationsexposition zu verhindern.
Viele Anwendungen verwenden ereignisgesteuerte Architektur als primäre Architektur. Sie können diesen Ansatz mit anderen Architekturstilen kombinieren, um eine Hybridarchitektur zu erstellen. Typische Kombinationen sind Microservices und Rohre und Filter. Integrieren Sie ereignisgesteuerte Architektur, um die Systemleistung zu verbessern, indem Engpässe beseitigt und während hoher Anforderungsvolumen Der Rückdruck bereitgestellt wird.
Bestimmte Domänen umfassen häufig mehrere Ereignishersteller, Verbraucher oder Ereigniskanäle. Änderungen an einer bestimmten Domäne können sich auf viele Komponenten auswirken.
Zugehörige Ressourcen
- Community-Diskussionsvideo zu den Überlegungen zur Auswahl zwischen Choreographie und Orchestrierung.