Microservices ohne Datenvervielfältigung

19

Ich finde es schwierig, Datenvervielfältigungen oder eine gemeinsam genutzte Datenbank selbst für das einfachste Mikrodienstdesign zu vermeiden, was mich glauben lässt, dass mir etwas fehlt. Hier ist ein grundlegendes Beispiel für das Problem, mit dem ich konfrontiert bin. Angenommen, jemand verwendet eine Webanwendung, um ein Inventar zu verwalten, dann würde er zwei Dienste benötigen. eine für das Inventar, das die Artikel und die Menge auf Lager verwaltet, und einen Benutzerservice, der die Benutzerdaten verwaltet. Wenn wir prüfen möchten, wer die Datenbank auf Lager hat, können wir der Datenbank die Benutzer-ID für den Inventarservice als Wert für den letzten Bestand hinzufügen.

Unter Verwendung der Anwendung möchten wir möglicherweise alle Artikel anzeigen, die zur Neige gehen, und eine Liste, von wem sie das letzte Mal eingelagert wurden, damit wir sie auffordern können, sie erneut aufzufüllen. Unter Verwendung der oben beschriebenen Architektur würde eine Anfrage an den Inventarservice gestellt, um die Artikeldetails aller Artikel abzurufen, bei denen die Menge kleiner als 5 ist. Dies würde eine Liste mit den Benutzer-IDs zurückgeben. Anschließend wird eine separate Anfrage an den Benutzerservice gesendet, um den Benutzernamen und die Kontaktdaten für die Liste der Benutzer-IDs abzurufen, die vom Inventarservice bezogen wurden.

Dies scheint schrecklich ineffizient zu sein, und es werden nicht mehr viele Dienste benötigt, bevor mehrere Anforderungen an verschiedene Dienst-APIs gesendet werden, die wiederum mehrere Datenbankabfragen durchführen. Eine Alternative besteht darin, die Benutzerdetails in den Inventardaten zu replizieren. Wenn ein Benutzer seine Kontaktdaten ändert, müssen wir die Änderung über alle anderen Dienste replizieren. Dies scheint jedoch nicht mit der begrenzten Kontextidee von Mikrodienstleistungen übereinzustimmen. Wir könnten auch eine einzige Datenbank verwenden und diese zwischen verschiedenen Diensten teilen und alle Probleme einer Integrationsdatenbank haben .

Was ist der richtige / beste Weg, dies umzusetzen?

Geraint Anderson
quelle
5
Willkommen im Paradoxon der Mikrodienste. Das, was die Dinge scheinbar einfacher macht, kann die Dinge tatsächlich komplexer machen.
Robert Harvey
Der "richtige" Weg ist derselbe wie immer: Finden Sie einen Weg, Dinge zu tun, die Ihren spezifischen Zielen am besten entsprechen.
Robert Harvey
1
@RobertHarvey Das ist immer der Fall, aber ich versuche, den Lehrbuch-Microservices-Weg zu verstehen. Sobald ich verstanden habe, wie es in einer idealen Welt funktionieren sollte, werde ich es gerne an meinen Anwendungsfall anpassen.
Geraint Anderson
1
Aber du stellst deine Frage in Bezug auf Effizienz, was eine nicht funktionierende Softwareanforderung ist. Sie lösen das Effizienzproblem, indem Sie die Datenbank direkt anfragen.
Robert Harvey
1
Ich wollte eine Frage genau so schreiben, wie Sie. Ich sehe in MSA immer noch keine Vorteile für einigermaßen einfache Webanwendungen. Ich denke, in vielen Fällen könnte Modularität erreicht werden, ohne die Dinge so komplex zu machen.
Glasnhost

Antworten:

9

Ich habe völlig übersehen, wo Du duplizieren musst.

Ein zentrales Prinzip von Mikrodiensten besteht darin, dass der Dienst die einzige Behörde ist. Das heißt, Inventar und Benutzerverwaltung können vollständig getrennt werden. Ich würde die Benutzerverwaltung so gestalten, dass sie nicht einmal weiß, dass das Inventarsystem existiert.

Aber ich würde das Inventarsystem so gestalten, dass es nie etwas über andere Benutzer als eine Benutzer-ID speichert. Das behebt Ihr Problem bei der Weitergabe von Benutzerdatenänderungen.

Dinge, die sowohl Inventarinformationen als auch Benutzerinformationen benötigen, wie Protokolle, Audits und Ausdrucke, werden nicht aktualisiert, wenn sich die Informationen ändern. Sie sind eine Aufzeichnung dessen, was war. Auch hier propagiert man keine Veränderung.

Wenn Sie also in jedem Fall die neuesten Benutzerinformationen wünschen, wenden Sie sich an den Benutzerinformationsdienst.

kandierte_orange
quelle
@Geraint: Können Sie genauer sagen, welche Art von Duplizierung in Ihrem System auftritt?
Robert Harvey
1
Vielen Dank. Die Vervielfältigung bezieht sich auf das Kopieren der Kontaktdaten des Benutzers an den Inventarservice, Sie haben dies jedoch behoben (dh es ist nicht erforderlich). Es scheint nicht intuitiv zu sein, von einer einzigen relationalen Datenbank, in der ich die Inventardaten und die Benutzerdaten mit einem Join abrufen konnte, zu zwei unterschiedlichen API-Aufrufen zu wechseln, bei denen der zweite erst beginnen kann, wenn der erste die Ergebnisse zurückgegeben hat. Aber ich denke, das ist Teil der Bewertung, ob ich Microservices oder etwas anderes benutze.
Geraint Anderson
Es ist derselbe Trick, den die DB anwenden würde, wenn sie beide verwalten würde. Sie kopieren keine Benutzerinformationen in die Inventartabelle. Sie geben ihm einen Fremdschlüssel. Die Benutzer-ID erledigt dienstübergreifend den gleichen Job. Mach es einfach einzigartig.
candied_orange
It seems counter-intuitive to move from a single relational database where I could get the inventory data and the user data with a joinDenken Sie daran, dass es "idealerweise" ein Geschäft pro Service gibt (oder mehr!). Es gibt also nichts wie "Verbinden" zwischen "Grenzen". Der Grund ist einfach: DB generiert eine Kopplung zwischen Diensten. Im Gegensatz zu @CandiedOrange können wir meines Erachtens ein Minimum an Daten von einem Dienst zu einem anderen duplizieren. Ich beziehe mich auf Daten, die sich wahrscheinlich nicht ändern werden. Wenn dies die Effizienz und Leistung verbessert (und beides erforderlich ist), würden die "Profis" wahrscheinlich die "Nachteile"
ausgleichen
@GeraintAnderson Ich meine, wenn Sie Effizienz benötigen (was per Definition keine funktionale Anforderung ist), gibt es Möglichkeiten, dies zu tun. Dh fordern Sie Datenseiten vom Inventarservice an (wie 10 Elemente), nehmen Sie jede Seite und verwenden Sie diese Seite, um Daten vom Benutzerservice anzufordern und am Ende zu aggregieren. Auf diese Weise behalten Sie Ihre Grenzen, während Sie die Parallelität unabhängiger Dienste nutzen. Machen Sie sich auch dann keine Sorgen, bis Sie festgestellt haben, dass es sich um einen echten Engpass in der Anwendung handelt, der behoben werden muss - das Warten auf eine zusätzliche halbe Sekunde bei einem 1-Sekunden-Übernachtjob ist für niemanden von Bedeutung.
Delioth
10

Ich finde es schwierig, Datenvervielfältigungen zu vermeiden ...

Laut dem Microsoft E-Book zur Microservice-Architektur ist an der Datenverdoppelung nichts auszusetzen. Grundsätzlich wird durch das Duplizieren von Daten die Entkopplung zwischen den Diensten verstärkt und ihre Rolle als einzelne Behörde gestärkt. Eine relevante Passage:

Und schließlich (und hier treten die meisten Probleme beim Erstellen von Mikrodiensten auf): Wenn Ihr erster Mikrodienst Daten benötigt, die ursprünglich anderen Mikrodiensten gehören, müssen Sie diese Daten nicht synchron anfordern. Replizieren oder verbreiten Sie stattdessen diese Daten (nur die von Ihnen benötigten Attribute) in die Datenbank des ursprünglichen Service, indem Sie die letztendliche Konsistenz verwenden (normalerweise mithilfe von Integrationsereignissen).

Maurits Moeys
quelle
1
Ich stimme überhaupt nicht zu. Es macht es schwieriger zu warten. Sie können Transaktionen zwischen Microservices implementieren, wenn etwas hinzugefügt, aktualisiert oder entfernt werden muss. Wenn Sie einen einzelnen Fehlerpunkt verhindern möchten, können Sie Request oder eine andere Art von Caching verwenden.
Alan Sereb
@ AlanSereb Es ist schwieriger zu pflegen, aber manchmal hat man keine andere Wahl. Was ist zum Beispiel, wenn Sie eine FK zwischen Objekten in zwei Datenbanken erstellen müssen? Die einzige Möglichkeit, die Konsistenz beim Ausführen von Abfragen in einer lokalen Datenbank sicherzustellen, ist eine Datenreplikation. Werfen
David D.
Genau. Ein weiterer großartiger Ansatz ist es, den Event-Sourcing-Weg zu gehen. Und lassen Sie alle Mutationen über die Event-Pipeline ausführen
ausführen Alan Sereb
3

Es wird eine Anforderung an den Inventarservice gesendet, um die Artikeldetails aller Artikel abzurufen, bei denen die Menge unter 5 liegt. Dadurch wird eine Liste mit den Benutzer-IDs zurückgegeben. Anschließend wird eine separate Anfrage an den Benutzerservice gesendet, um den Benutzernamen und die Kontaktdaten für die Liste der Benutzer-IDs abzurufen, die vom Inventarservice bezogen wurden.

In der Tat, ja.

Zugegeben, in einem Monolithen könnten Sie ein Inventarmodell haben, das Sie nach den relevanten Elementen abfragen, das in ein Benutzermodell einspeisen und dieselben Daten erhalten.

Oder Sie könnten noch weiter gehen, wenn Sie sie in derselben relationalen Datenbank haben und SQL schreiben, und die Datenbank die Inventar- und Benutzertabelle übernimmt, etwas magisch ist und Sie die Daten erhalten, nach denen Sie suchen.

Unabhängig davon , wie Sie es tun, irgendwo wird Code sein, der im Wesentlichen eine Liste von Benutzer - IDs aus dem Inventar - System holt, speist sie in das Benutzersystem und stellt eine Liste von Daten.

Die Frage, die Sie beantworten müssen, betrifft die Leistung und Wartung sowie andere "weiche" Eigenschaften.

Der Hauptvorteil von Microservices ist die Skalierung.Wenn Sie zehntausend Benutzer auf einem Computer haben und es etwas träge ist, können Sie einen weiteren Computer hinzufügen, und das System wird doppelt so schnell. Fügen Sie acht weitere hinzu und es ist zehnmal so schnell. (Lineare Skalierung ist wahrscheinlich optimistisch, aber es ist das Ideal und nicht so unvernünftig, darauf zu hoffen.)

Und das ist pro Service . Wenn das Inventarsystem der Engpass ist, wird es für mehr als nur Berichte über Benutzer verwendet. Sie können nur diesem Service weitere Computer hinzufügen . Die Maschinen können auch spezialisiert werden; Dieser Dienst benötigt viel Speicher, führt umfangreiche Berechnungen durch und benötigt mehr CPU.

Wenn Sie die Skalierung nicht benötigen, gibt es einen weiteren Vorteil von Microservices: Sie sind modular aufgebaut . Natürlich können monolithische Apps auch modular sein, und Sie haben eine normalisierte Datenbank und ... aber in der Praxis sind die Wände zwischen den Modulen im besten Fall wie Glaswände und im schlechtesten Fall wie Linien im Sand. Microservices sind durch massiven Stahl getrennt.

Wenn Ihr Benutzersystem buchstäblich in Brand gerät, hat dies keinerlei Auswirkungen auf Ihr Inventarsystem. Sie können keine hübschen Berichte darüber drucken, wer was auf Lager hat, aber Kunden können sicher Bestellungen aufgeben, wenn sie wissen, dass die auf Lager befindlichen Artikel dort sind.

Und Sie duplizieren Daten in Microservices nicht mehr als in einer relationalen Datenbank (*). In einer relationalen Datenbank können Sie einen Join ausführen, und das Äquivalent besteht darin, die Listen wie beschrieben im Code zusammenzuführen.

Sie können auch eine Ansicht hinzufügen . Das Äquivalent ist, einen neuen Dienst hinzuzufügen, der die Zusammenführung für Sie ausführt. das würde zu drei Anfragen führen; eins auf den neuen Dienst und dieser Dienst führt dann die ursprünglichen zwei aus. Relationale Datenbanken haben ausgefallene Dinge, die Ansichten optimieren und auf Serviceebene implementiert werden müssen. Du bekommst es nicht "kostenlos".

Das Zwischenspeichern unterscheidet sich von der Duplizierung von Daten darin, dass Sie, wenn zwei Werte nicht übereinstimmen, wissen, welcher falsch ist. Es wird häufig in Mikrodiensten verwendet, um die Verfügbarkeit auf Kosten der Konsistenz zu erhöhen (CAP-Theorem). Da relationale Datenbanken die Verfügbarkeit auf dem Altar der Konsistenz vollständig unterbieten, ist dies bei ihnen seltener der Fall. Ich würde sagen, dass an Microservices nichts anhaftet, was das Caching erleichtert, aber in der Praxis ist das Caching ein Hauptanliegen und erleichtert das Caching in Microservices .

(*) Wenn es Sinn macht, Daten in einem Microservice-Schwarm zu duplizieren, dann wäre es wahrscheinlich sinnvoll, in der entsprechenden relationalen Datenbank zu.

Odalrick
quelle
3
Ihre Antwort hat mir wirklich gut gefallen, bis der Teil "Daten in Microservices nicht duplizieren". Ich denke, es gibt Fälle, in denen die Duplizierung von Daten der richtige Ansatz ist. Es verbessert Fehlertoleranz und Autonomie. Wenn der Benutzerservice ausfällt, kann der Inventarservice weiterhin eine Liste mit wenig Inventar anzeigen, mit wem sie zuletzt vorrätig waren.
Peter Pompeji
1
@ Peterpompeii Ich würde das Caching nennen, nicht die Duplizierung von Daten. Beim Duplizieren von Daten müssen zwei Bereiche für ein Datum aktualisiert werden. Das Zwischenspeichern erfolgt, wenn ein Bereich vorhanden ist, und die automatische Weitergabe an die anderen Bereiche. Auch sagte ich mehr als relational. Wenn es in einer relationalen Datenbank sinnvoll ist, Daten zu duplizieren, ist dies in einem Microservice sinnvoll. Ich denke, wir sind uns einig und dieser Teil könnte klarer sein, aber ich habe momentan nur ein Telefon, daher wird der Text momentan nicht aktualisiert.
Odalrick
@PeterPompeii Hoffe, der hinzugefügte Abschnitt über das Zwischenspeichern behebt einige Ihrer Bedenken.
Odalrick
1
@Odalrick, was Sie beschrieben haben, klingt nach Datenreplikation. Replikation und Zwischenspeicherung sind beide Arten des Duplizierens von Daten. Replikation ist, wenn garantiert wird, dass eine Kopie immer alle erforderlichen Daten enthält. Caching ist auf Abruf möglich. Caching kann fehlschlagen. Das Zwischenspeichern der Verfügbarkeit ist weniger sinnvoll als das Zwischenspeichern der Leistung. TL; DR Wenn Sie eine vollständige Kopie von etwas mit ausreichender Konsistenz speichern, ist dies kein Cache.
Brandon
1
@Brandon Ein weiterer Unterschied zwischen Replikation und Zwischenspeicherung besteht darin, dass Sie wissen, welche Daten falsch sind, wenn es einen Unterschied gibt. Die Replikation definiert einige Regeln zum Zusammenführen der Daten. Caching hingegen ist immer : Der Cache ist falsch.
Odalrick