Ich komme immer wieder auf diese Qualitätssicherung zurück. Und ich fand die vorhandenen Antworten nicht nuanciert genug, also füge ich diese hinzu.
TL; DR. Ja oder Nein, abhängig von Ihrer Event-Sourcing-Nutzung.
Es gibt zwei Hauptarten von Event-Sourcing-Systemen, die mir bekannt sind.
Downstream-Ereignisprozessoren = Ja
In einem solchen System ereignen sich Ereignisse in der realen Welt und werden als Fakten aufgezeichnet. Zum Beispiel ein Lagersystem zur Verfolgung von Produktpaletten. Grundsätzlich gibt es keine widersprüchlichen Ereignisse. Alles ist schon passiert, auch wenn es falsch war. (Dh Palette 123456 auf LKW A gestellt, aber für LKW B geplant.) Später werden die Fakten über Meldemechanismen auf Ausnahmen überprüft. Kafka scheint für diese Art von nachgeschalteter Ereignisverarbeitungsanwendung gut geeignet zu sein.
In diesem Zusammenhang ist es verständlich, warum Kafka-Leute es als Event-Sourcing-Lösung befürworten. Weil es ziemlich ähnlich ist, wie es beispielsweise bereits in Klick-Streams verwendet wird. Personen, die den Begriff Event Sourcing (im Gegensatz zu Stream Processing) verwenden, beziehen sich jedoch wahrscheinlich auf die zweite Verwendung ...
Anwendungsgesteuerte Wahrheitsquelle = Nr
Diese Art von Anwendung deklariert ihre eigenen Ereignisse als Ergebnis von Benutzeranforderungen, die die Geschäftslogik durchlaufen. Kafka funktioniert in diesem Fall aus zwei Hauptgründen nicht gut.
Fehlende Entitätsisolation
Dieses Szenario erfordert die Fähigkeit, den Ereignisstrom für eine bestimmte Entität zu laden. Der häufigste Grund hierfür ist die Erstellung eines transienten Schreibmodells für die Geschäftslogik zur Verarbeitung der Anforderung. Dies zu tun ist in Kafka unpraktisch. Die Verwendung von Topic-per-Entity kann dies ermöglichen, es sei denn, dies ist kein Starter, wenn Tausende oder Millionen von Entitäten vorhanden sind. Dies liegt an technischen Einschränkungen in Kafka / Zookeeper.
Einer der Hauptgründe für die Verwendung eines vorübergehenden Schreibmodells auf diese Weise besteht darin, Änderungen der Geschäftslogik kostengünstig und einfach bereitzustellen.
Die Verwendung von Topic-per-Type wird stattdessen für Kafka empfohlen. Dies würde jedoch das Laden von Ereignissen für jede Entität dieses Typs erfordern , nur um Ereignisse für eine einzelne Entität abzurufen. Da Sie anhand der Protokollposition nicht erkennen können, welche Ereignisse zu welcher Entität gehören. Selbst wenn Snapshots verwendet werden , um von einer bekannten Protokollposition aus zu starten, kann dies eine erhebliche Anzahl von Ereignissen sein, die durchlaufen werden müssen.
Fehlende Konflikterkennung
Zweitens können Benutzer aufgrund gleichzeitiger Anforderungen an dieselbe Entität Rennbedingungen erstellen. Es kann durchaus unerwünscht sein, widersprüchliche Ereignisse zu speichern und nachträglich zu beheben. Daher ist es wichtig, widersprüchliche Ereignisse verhindern zu können. Um die Anforderungslast zu skalieren, werden häufig zustandslose Dienste verwendet, während Schreibkonflikte durch bedingte Schreibvorgänge verhindert werden (nur schreiben, wenn das letzte Entitätsereignis #x war). Aka Optimistische Parallelität. Kafka unterstützt keine optimistische Parallelität. Selbst wenn es auf Themenebene unterstützt würde, müsste es bis auf die Entitätsebene reichen, um effektiv zu sein. Um Kafka zu verwenden und widersprüchliche Ereignisse zu vermeiden, müssen Sie auf Anwendungsebene einen statusbehafteten, serialisierten Writer verwenden. Dies ist eine wesentliche architektonische Anforderung / Einschränkung.
Weitere Informationen
Update pro Kommentar
Der Kommentar wurde gelöscht, aber die Frage war ungefähr so: Was verwenden die Leute dann für die Speicherung von Ereignissen?
Es scheint, dass die meisten Leute ihre eigene Ereignisspeicherimplementierung auf eine vorhandene Datenbank rollen. Für nicht verteilte Szenarien wie interne Back-Ends oder eigenständige Produkte ist gut dokumentiert, wie ein SQL-basierter Ereignisspeicher erstellt wird. Darüber hinaus stehen Bibliotheken für verschiedene Arten von Datenbanken zur Verfügung. Es gibt auch EventStore , der für diesen Zweck erstellt wurde.
In verteilten Szenarien habe ich verschiedene Implementierungen gesehen. Das Panther-Projekt von Jet verwendet Azure CosmosDB mit der Funktion "Feed ändern", um Listener zu benachrichtigen. Eine andere ähnliche Implementierung, von der ich in AWS gehört habe, ist die Verwendung von DynamoDB mit seiner Streams-Funktion, um Listener zu benachrichtigen. Der Partitionsschlüssel sollte wahrscheinlich die Stream-ID für die beste Datenverteilung sein (um das Ausmaß der Überbereitstellung zu verringern). Eine vollständige Wiedergabe über Streams in Dynamo ist jedoch teuer (lesbar und kostenmäßig). Daher wurde dieses Gerät auch für Dynamo Streams eingerichtet, um Ereignisse in S3 zu sichern. Wenn ein neuer Listener online geht oder ein vorhandener Listener eine vollständige Wiedergabe wünscht, liest er S3, um zuerst aufzuholen.
Mein aktuelles Projekt ist ein mandantenfähiges Szenario, und ich habe mein eigenes auf Postgres gerollt. So etwas wie Citus scheint für die Skalierbarkeit geeignet zu sein, die Partitionierung durch Tentant + Stream.
Kafka ist in verteilten Szenarien immer noch sehr nützlich. Es ist kein triviales Problem, die Ereignisse jedes Dienstes anderen Diensten auszusetzen. Ein Event-Store ist normalerweise nicht dafür gebaut, aber genau das macht Kafka gut. Jeder Dienst hat seine eigene interne Wahrheitsquelle (kann Ereignisspeicherung oder auf andere Weise sein), hört jedoch auf Kafka, um zu wissen, was "außerhalb" geschieht. Der Dienst kann auch Ereignisse an Kafka senden, um die "Außenwelt" über interessante Dinge zu informieren, die der Dienst getan hat.