Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Tipp
Dieser Inhalt ist ein Auszug aus dem eBook .NET Microservices Architecture for Containerized .NET Applications, verfügbar auf .NET Docs oder als kostenlose herunterladbare PDF, die offline gelesen werden kann.
Wie bereits beschrieben, veröffentlicht ein Microservice, wenn Sie ereignisbasierte Kommunikation verwenden, ein Ereignis, wenn etwas Bemerkenswertes geschieht, z. B. wenn eine Geschäftsentität aktualisiert wird. Andere Microservices abonnieren diese Ereignisse. Wenn ein Microservice ein Ereignis empfängt, kann er seine eigenen Geschäftsentitäten aktualisieren, was dazu führen kann, dass mehr Ereignisse veröffentlicht werden. Dies ist das Wesen des letztendlichen Konsistenzkonzepts. Dieses Veröffentlichungs-/Abonnierungssystem wird in der Regel mithilfe einer Implementierung eines Ereignisbus ausgeführt. Der Ereignisbus kann als Schnittstelle mit der API entworfen werden, die zum Abonnieren und Kündigen von Ereignissen und zum Veröffentlichen von Ereignissen erforderlich ist. Sie kann auch eine oder mehrere Implementierungen basierend auf jeder Prozess- oder Messagingkommunikation haben, z. B. eine Messagingwarteschlange oder einen Servicebus, der asynchrone Kommunikation und ein Veröffentlichungs-/Abonnierungsmodell unterstützt.
Sie können Ereignisse verwenden, um Geschäftstransaktionen zu implementieren, die sich über mehrere Dienste erstrecken, was Ihnen letztendlich die Konsistenz zwischen diesen Diensten ermöglicht. Eine schließlich konsistente Transaktion besteht aus einer Reihe von verteilten Aktionen. Bei jeder Aktion aktualisiert der Microservice eine Geschäftsentität und veröffentlicht ein Ereignis, das die nächste Aktion auslöst. Beachten Sie, dass die Transaktion nicht den zugrunde liegenden Persistenz- und Ereignisbus umfasst, sodass idempotenz behandelt werden muss. Abbildung 6-18 unten zeigt ein PriceUpdated-Ereignis, das über einen Ereignisbus veröffentlicht wird, sodass die Preisaktualisierung an den Basket und andere Microservices weitergegeben wird.
Abbildung 6-18. Ereignisgesteuerte Kommunikation basierend auf einem Ereignisbus
In diesem Abschnitt wird beschrieben, wie Sie diese Art der Kommunikation mit .NET mithilfe einer generischen Ereignisbusschnittstelle implementieren können, wie in Abbildung 6-18 dargestellt. Es gibt mehrere potenzielle Implementierungen, die jeweils eine andere Technologie oder Infrastruktur wie RabbitMQ, Azure Service Bus oder einen anderen Open Source- oder kommerziellen Servicebus von Drittanbietern verwenden.
Verwendung von Nachrichtenbrokern und Dienstbussen für Produktionssysteme
Wie im Abschnitt "Architektur" erwähnt, können Sie aus mehreren Messagingtechnologien für die Implementierung Ihres abstrakten Ereignisbus auswählen. Diese Technologien befinden sich jedoch auf unterschiedlichen Ebenen. Beispielsweise ist RabbitMQ, ein Nachrichtenbrokertransport, auf einer niedrigeren Ebene als kommerzielle Produkte wie Azure Service Bus, NServiceBus, MassTransit oder Brighter. Die meisten dieser Produkte können entweder über RabbitMQ oder Azure Service Bus arbeiten. Ihre Produktauswahl hängt davon ab, wie viele Features und wie viele out-of-the-box Skalierbarkeit Sie für Ihre Anwendung benötigen.
Für die Implementierung von nur einem Ereignisbus-Proof-of-Concepts für die Entwicklungsumgebung wie im eShopOnContainers-Beispiel ist eine einfache Implementierung zusätzlich zu einer als Container ausgeführten RabbitMQ-Installation möglicherweise ausreichend. Aber für unternehmenskritische und Produktionssysteme, die eine hohe Skalierbarkeit benötigen, sollten Sie Azure Service Bus bewerten und verwenden.
Wenn Sie allgemeine Abstraktionen und umfangreichere Features wie Sagas für lange laufende Prozesse benötigen, die die verteilte Entwicklung vereinfachen, sind andere kommerzielle und Open-Source-Servicebusse wie NServiceBus, MassTransit und Brighter zu bewerten. In diesem Fall sind die zu verwendenden Abstraktionen und die zu verwendende API diejenigen, die von diesen allgemeinen Service Bussen bereitgestellt werden, und nicht Ihre eigenen Abstraktionen (wie die unter eShopOnContainers bereitgestellten einfachen Ereignisbusabstraktionen). Zu diesem Zweck können Sie die geforkten eShopOnContainers mithilfe von NServiceBus (zusätzliches abgeleitetes Beispiel, durch Particular Software implementiert) untersuchen.
Natürlich könnten Sie stets Ihre eigenen Service-Bus-Features auf Basis von Technologien wie RabbitMQ und Docker entwickeln, aber die Arbeit, die erforderlich ist, um das Rad neu zu erfinden, ist möglicherweise zu aufwendig und kostenintensiv für eine benutzerdefinierte Unternehmensanwendung.
Zur Wiederholung: Die Event-Bus-Abstraktionen und -Implementierung im eShopOnContainers-Beispiel sollen nur als ein Machbarkeitsnachweis verwendet werden. Nachdem Sie sich entschieden haben, dass Sie über asynchrone und ereignisgesteuerte Kommunikation verfügen möchten, wie im aktuellen Abschnitt erläutert, sollten Sie das Servicebusprodukt auswählen, das Ihren Anforderungen für die Produktion am besten entspricht.
Integrationsereignisse
Integrationsereignisse werden verwendet, um den Domänenstatus über mehrere Mikroservices oder externe Systeme hinweg zu synchronisieren. Diese Funktionalität erfolgt durch Veröffentlichen von Integrationsereignissen außerhalb des Microservice. Wenn ein Ereignis in mehreren Empfänger-Microservices veröffentlicht wird (in so vielen Microservices wie das Integrationsereignis abonniert ist), wird das Ereignis von dem entsprechenden Ereignishandler in jedem Empfänger-Microservice behandelt.
Bei einem Integrationsereignis handelt es sich im Wesentlichen um eine Klasse zum Speichern von Daten wie im folgenden Beispiel:
public class ProductPriceChangedIntegrationEvent : IntegrationEvent
{
public int ProductId { get; private set; }
public decimal NewPrice { get; private set; }
public decimal OldPrice { get; private set; }
public ProductPriceChangedIntegrationEvent(int productId, decimal newPrice,
decimal oldPrice)
{
ProductId = productId;
NewPrice = newPrice;
OldPrice = oldPrice;
}
}
Die Integrationsereignisse können auf anwendungsebene jedes Microservice definiert werden, sodass sie von anderen Microservices abgekoppelt werden, auf eine Weise, die mit der Definition von ViewModels auf dem Server und Client vergleichbar ist. Was nicht empfohlen wird, ist das Freigeben einer gemeinsamen Integrationsereignissebibliothek für mehrere Microservices; Dies wäre eine Kopplung dieser Microservices mit einer einzelnen Ereignisdefinitionsdatenbibliothek. Sie möchten dies aus denselben Gründen nicht tun, aus denen Sie kein gemeinsames Domänenmodell über mehrere Microservices hinweg gemeinsam nutzen möchten: Microservices müssen vollständig autonom sein. Weitere Informationen finden Sie in diesem Blogbeitrag zur Datenmenge, die in Ereignissen abgelegt werden soll. Gehen Sie vorsichtig vor und übertreiben Sie es nicht, da dieser andere Blogbeitrag das Problem von datenarmen Nachrichten beschreibt. Ihr Design Ihrer Veranstaltungen sollte für die Bedürfnisse ihrer Verbraucher "genau richtig" sein.
Es gibt nur einige Arten von Bibliotheken, die Sie über Microservices hinweg freigeben sollten. Eine ist Bibliotheken, die endgültige Anwendungsblöcke sind, z. B. die Event Bus-Client-API, wie in eShopOnContainers. Eine andere ist Bibliotheken, die Tools darstellen, die auch als NuGet-Komponenten freigegeben werden können, z. B. JSON-Serialisierer.
Der Ereignisbus
Ein Ereignisbus ermöglicht die Publish/Subscribe-Kommunikation zwischen Microservices, ohne dass die Komponenten explizit voneinander wissen müssen, wie in Abbildung 6-19 dargestellt.
Abbildung 6-19. Veröffentlichen/Abonnieren mit einem Ereignisbus
Das obige Diagramm zeigt, dass der Microservice A an den Event-Bus veröffentlicht, der die Nachrichten an die abonnierten Microservices B und C verteilt, ohne dass der Herausgeber die Abonnenten kennen muss. Der Ereignisbus steht in Zusammenhang mit dem Observer-Muster und dem Publish-Subscribe-Muster.
Beobachtermuster
Im Beobachtermuster benachrichtigt Ihr primäres Objekt (bekannt als Observable) andere interessierte Objekte (als Beobachter bezeichnet) mit relevanten Informationen (Ereignissen).
Muster „Veröffentlichen/Abonnieren“
Der Zweck des Musters "Veröffentlichen/Abonnieren " entspricht dem Beobachtermuster: Sie möchten andere Dienste benachrichtigen, wenn bestimmte Ereignisse stattfinden. Es gibt jedoch einen wichtigen Unterschied zwischen dem Observer-Muster und dem Pub/Sub-Muster. Im Beobachtermuster wird die Übertragung direkt von den observablen bis hin zu den Beobachtern durchgeführt, so dass sie einander "kennen". Bei Verwendung eines Pub/Sub-Musters gibt es jedoch eine dritte Komponente, die als Broker oder Nachrichtenbroker oder Ereignisbus bezeichnet wird, der sowohl vom Herausgeber als auch vom Abonnenten bekannt ist. Daher werden der Herausgeber und die Abonnenten bei Verwendung des Pub/Sub-Musters durch den erwähnten Ereignisbus oder Nachrichtenbroker exakt entkoppelt.
Der Vermittler oder Ereignisbus
Wie erreichen Sie anonymität zwischen Herausgeber und Abonnent? Eine einfache Möglichkeit ist, dass ein Vermittler sich um die gesamte Kommunikation kümmert. Ein Ereignisbus ist ein solcher Vermittler.
Ein Ereignisbus besteht in der Regel aus zwei Teilen:
Die Abstraktion oder Schnittstelle.
Eine oder mehrere Implementierungen.
In Abbildung 6-19 wird deutlich, dass der Ereignisbus aus der Sicht der Anwendung lediglich einen Veröffentlichen/Abonnieren-Kanal darstellt. Die Implementierung dieser asynchronen Kommunikation kann variieren. Es kann mehrere Implementierungen haben, sodass Sie je nach Umgebungsanforderungen (z. B. Produktions- und Entwicklungsumgebungen) zwischen ihnen wechseln können.
In Abbildung 6-20 können Sie eine Abstraktion eines Ereignisbus mit mehreren Implementierungen basierend auf Infrastruktur-Messagingtechnologien wie RabbitMQ, Azure Service Bus oder einem anderen Ereignis-/Nachrichtenbroker sehen.
Abbildung 6- 20. Mehrere Implementierungen eines Ereignisbus
Es ist gut, dass der Ereignisbus über eine Schnittstelle definiert wird, damit er mit mehreren Technologien wie RabbitMQ, Azure Service Bus oder anderen implementiert werden kann. Wie bereits erwähnt, ist die Verwendung ihrer eigenen Abstraktionen (die Ereignisbusschnittstelle) jedoch nur dann gut, wenn Sie grundlegende Ereignisbusfeatures benötigen, die von Ihren Abstraktionen unterstützt werden. Wenn Sie umfangreichere Servicebusfunktionen benötigen, sollten Sie wahrscheinlich die API und Abstraktionen verwenden, die von Ihrem bevorzugten kommerziellen Servicebus anstelle Ihrer eigenen Abstraktionen bereitgestellt werden.
Definieren einer Ereignisbusschnittstelle
Beginnen wir mit einem Implementierungscode für die Ereignisbusschnittstelle und möglichen Implementierungen für Erkundungszwecke. Die Schnittstelle sollte generisch und unkompliziert sein, wie in der folgenden Schnittstelle.
public interface IEventBus
{
void Publish(IntegrationEvent @event);
void Subscribe<T, TH>()
where T : IntegrationEvent
where TH : IIntegrationEventHandler<T>;
void SubscribeDynamic<TH>(string eventName)
where TH : IDynamicIntegrationEventHandler;
void UnsubscribeDynamic<TH>(string eventName)
where TH : IDynamicIntegrationEventHandler;
void Unsubscribe<T, TH>()
where TH : IIntegrationEventHandler<T>
where T : IntegrationEvent;
}
Die Publish
Methode ist einfach. Der Ereignisbus sendet das Integrationsereignis, das an ihn übergeben wurde, an jeden Microservice oder sogar eine externe Anwendung, die dieses Ereignis abonniert hat. Diese Methode wird vom Microservice verwendet, der das Ereignis veröffentlicht.
Die Subscribe
Methoden (je nach Argumenten können mehrere Implementierungen vorhanden sein) werden von den Microservices verwendet, die Ereignisse empfangen möchten. Diese Methode hat zwei Argumente. Das erste ist das Integrationsereignis, das abonniert werden soll (IntegrationEvent
). Das zweite Argument ist der Integrationsereignishandler (oder die Rückrufmethode) IIntegrationEventHandler<T>
, der ausgeführt werden soll, wenn der Empfänger-Mikrodienst diese Integrationsereignisnachricht erhält.
Weitere Ressourcen
Einige produktionsfähige Messaging-Lösungen:
Azure Service Bus
https://learn.microsoft.com/azure/service-bus-messaging/NServiceBus
https://particular.net/nservicebusMassTransit
https://masstransit-project.com/