Wie lassen sich Daten über Microservices hinweg richtig synchronisieren?


17

Ich bin relativ neu in der Microservice-Architektur. Wir haben eine mittelgroße Webanwendung und ich wäge die Vor- und Nachteile der Aufteilung in Microservices ab, anstatt eines monolithischen Systems, das wir jetzt entwickeln.

Soweit ich es verstehe, betrachten Microservices Aund Bvon denen jeder stützen sich auf eine Teilmenge der Daten, die der andere hat. Wenn in einer Nachricht angegeben wird A, dass sich etwas geändert hat, Bkann diese Nachricht verwendet und eine lokale Kopie der AInformationen repliziert werden B.

Was passiert jedoch, wenn Bdas Gerät ausfällt und nach einiger Zeit wieder hochfährt? Während dieser Ausfallzeit Ahat zwei weitere Nachrichten veröffentlicht. Woher weiß Bich, wie meine lokale Kopie der AInformationen aktualisiert wird ?

Zugegeben, wenn Bes sich um den einzigen Verbraucher in der AWarteschlange handelt, kann er mit dem Lesen beginnen, sobald er wieder online ist. Was ist jedoch, wenn andere Verbraucher in der Warteschlange sind und diese Nachrichten verbraucht werden?

Genauer gesagt : Wenn bei einem UsersDienst die E-Mail-Adresse aktualisiert wird, während ein BillingMikrodienst nicht verfügbar ist, wird der BillingMikrodienst dann erneut angezeigt. Woher weiß der Dienst, dass die E-Mail aktualisiert wurde?

Wenn microservices wieder auftauchen, wird dann eine Sendung gesendet, die sagt: "Hey, ich bin wieder auf, gib mir all deine aktuellen Informationen."

Was wären die branchenweit besten Vorgehensweisen für die Datensynchronisierung?


1
Um dies nach Möglichkeit zu vermeiden.
Telastyn

1
Warum muss Ordersman etwas wissen Users?
kdgregory

Es ist nur ein Beispiel. Ersetzen Sie die beiden durch das, was Sie wollen, was Sinn macht.
Noblerare

Ein Fan-Out-Routing behebt das Problem, dass Ihre Nachricht von jemand anderem verarbeitet wird. Aber es ist wirklich unklar, was Sie erreichen wollen.
Ewan

@Ewan Ich habe meinen ursprünglichen Beitrag aktualisiert, um besser zu erklären, was ich zu fragen versuche.
Noblerare

Antworten:


6

Nachdem ich ein bisschen recherchiert hatte, stieß ich auf diesen Artikel, aus dem ich einige Zitate herausgezogen habe, die meiner Meinung nach hilfreich für das sind, was ich erreichen möchte (und für zukünftige Leser). Dies bietet eine Möglichkeit, ein reaktives Programmiermodell über ein imperatives Programmiermodell zu übernehmen.

Event-Sourcing

Die Idee dabei ist, den Statusübergang jeder Anwendung in Form eines unveränderlichen Ereignisses darzustellen. Ereignisse werden dann in einem Protokoll oder Journal gespeichert, sobald sie auftreten (auch als "Ereignisspeicher" bezeichnet). Sie können auch auf unbestimmte Zeit abgefragt und gespeichert werden, um darzustellen, wie sich der Status der Anwendung im Laufe der Zeit insgesamt entwickelt hat.

Dies trägt dazu bei, dass, wenn ein Mikrodienst ausfällt, andere Ereignisse, die für ihn relevant sind, veröffentlicht werden und Ereignisse beispielsweise von anderen Instanzen dieses Mikrodiensts verbraucht werden, auf den dieser Mikrodienst beim erneuten Aufrufen Bezug nehmen kann event store, um alle abzurufen Ereignisse, die es während der Periode verpasste, in der es unterging.

Apache Kafka als Event Broker

Erwägen Sie die Verwendung von Apache Kafka, das Tausende von Ereignissen pro Sekunde speichern und versenden kann und über integrierte Replikations- und Fehlertoleranzmechanismen verfügt. Es verfügt über einen permanenten Speicher mit Ereignissen, die auf unbestimmte Zeit auf der Festplatte gespeichert und zu jedem Zeitpunkt (jedoch nicht entfernt) aus dem Topic (Kafkas ausgefallene Warteschlange), an den sie übermittelt wurden, konsumiert werden können.

Den Ereignissen werden dann Offsets zugewiesen, die sie innerhalb des Themas eindeutig identifizieren. Kafka kann die Offsets selbst verwalten und auf einfache Weise "höchstens einmal" oder "mindestens einmal" Übermittlungssemantik bereitstellen. Sie können jedoch auch ausgehandelt werden, wenn ein Ereigniskonsument einem Thema beitritt Dies ermöglicht es Microservices, Ereignisse von jedem beliebigen Ort aus zu konsumieren - in der Regel von dem Ort an, an dem der Konsument aufgehört hat. Wenn der zuletzt verbrauchte Ereignisversatz im lokalen Speicher des Dienstes transaktionell beibehalten wird, wenn der Verwendungszweck "erfolgreich abgeschlossen" ist, kann dieser Versatz leicht verwendet werden, um eine "genau einmalige" Ereignisübermittlungssemantik zu erzielen.

Wenn sich Verbraucher bei Kafka identifizieren, zeichnet Kafka auf, welche Nachrichten an welchen Verbraucher übermittelt wurden, damit er sie nicht erneut bereitstellt.

Sagas

Bei komplexeren Anwendungsfällen, bei denen die Kommunikation zwischen verschiedenen Diensten tatsächlich erforderlich ist, muss die Verantwortung für die Ausführung des Anwendungsfalls klar erkannt werden. Der Anwendungsfall ist dezentralisiert und wird erst dann beendet, wenn alle beteiligten Dienste ihre Aufgabe als erfolgreich abgeschlossen anerkennen. Andernfalls muss der gesamte Anwendungsfall fehlschlagen Korrekturmaßnahmen müssen ausgelöst werden, um einen ungültigen lokalen Status zurückzusetzen.

Dies ist, wenn die Saga ins Spiel kommt. Eine Saga ist eine Folge lokaler Transaktionen. Jede lokale Transaktion aktualisiert die Datenbank und veröffentlicht eine Nachricht oder ein Ereignis, um die nächste lokale Transaktion in der Saga auszulösen. Wenn eine lokale Transaktion fehlschlägt, weil sie gegen eine Geschäftsregel verstößt, führt die Saga eine Reihe von Ausgleichstransaktionen aus, die die durch die vorhergehenden lokalen Transaktionen vorgenommenen Änderungen rückgängig machen. Lesen Sie dies für weitere Informationen.


Ich verstehe immer noch nicht, warum Sie eine so komplizierte Struktur bauen wollen. In der Regel ist es viel einfacher, wenn jeder Dienst nur seine eigenen Daten enthält und diese auf Anfrage an andere Dienste weitergibt.
J. Fabian Meier

^ Aber es wird die Verfügbarkeit des Systems verringern. Die komplizierte Struktur kann gerechtfertigt sein, wenn eine hohe Belastbarkeit erforderlich ist.
Avmohan

4

Ich würde Ihre Idee, "die Daten an alle anderen Microservices zu senden", in Frage stellen.

Wenn ein Abrechnungsdienst eine E-Mail-Adresse benötigt, fragt er normalerweise nur den Adressdienst nach der E-Mail-Adresse des jeweiligen Kunden. Es muss keine Kopie aller Adressdaten enthalten und wird auch nicht informiert, wenn sich etwas ändert. Es fragt nur und erhält die Antwort von den neuesten Daten.


Ich denke, diese Antwort ist genau richtig. Es werden viele Probleme im Zusammenhang mit der Synchronisation beseitigt. Tatsächlich befasse ich mich gerade mit Code, der solche Probleme aufweist, da verschiedene Dienste Kopien von Informationen aufbewahren und solche Synchronisierungsprobleme haben.
DaveG

2
Danke für deine Antwort. Warum sind dann ein Pub / Sub-Modell und Nachrichtenwarteschlangen erforderlich? Wenn wir versuchen, Daten zu "ziehen", anstatt sie zu "pushen", sind wir besorgt über die Service-Latenz.
Noblerare

AFAIK, Ihr Service muss nicht sofort reagieren, wenn sich etwas ändert (wie in einem Pub / Sub), sondern benötigt gelegentlich Daten. Dann würde ich es einfach ziehen. Wenn Sie sich über die Latenz Gedanken machen, können Sie die Daten zwischenspeichern. Dies geht jedoch wiederum zu Lasten der Unkenntnis, ob die Daten aktuell sind. Wenn Ihre Dateien groß sind, können Sie auch fragen, ob sich etwas geändert hat, bevor Sie etwas erneut abrufen.
J. Fabian Meier

Beachten Sie, dass diese Lösung mit einer engen Kopplung des abhängigen Dienstes verbunden ist. Dies bedeutet, dass die E-Mail-Adresse nicht verfügbar ist, wenn der Benutzerdienst nicht verfügbar ist. Eine der ersten Überlegungen, die Services zunächst so aufzuteilen, dass sie unabhängig voneinander bereitgestellt, skaliert usw. werden können. Wenn alle Services ohne Cache oder Garantie für hohe Verfügbarkeit direkt miteinander kommunizieren, sind sie alle ausgefallen, wenn ein System ausfällt gehen.
dukethrash

@dukethrash Dann mach sie hochverfügbar.
J. Fabian Meier

0

Sie können eine normale Ereigniswarteschlange durch ein Herausgeber- / Abonnentenmodell ersetzen, bei dem der ADienst eine neue Nachricht mit dem Thema T veröffentlicht und der BTyp der Microservices dasselbe Thema abonniert.

Im Idealfall handelt Bes sich um einen zustandslosen Dienst, der einen getrennten Persistenzdienst verwendet, sodass eine ausgefallene BDienstinstanz ersetzt wird, indem eine oder mehrere BDienstinstanzen erstellt werden, um ihre Arbeit fortzusetzen und aus demselben gemeinsam genutzten Persistenzdienst zu lesen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.