it-swarm.com.de

Was ist die am meisten akzeptierte Transaktionsstrategie für Microservices?

Eines der Hauptprobleme, das ich in einem System mit Microservices gesehen habe, ist die Funktionsweise von Transaktionen, wenn sie sich über verschiedene Services erstrecken. In unserer eigenen Architektur haben wir verteilte Transaktionen verwendet, um dies zu beheben, aber sie haben ihre eigenen Probleme. Besonders Deadlocks waren bisher ein Schmerz.

Eine andere Option scheint eine Art maßgeschneiderter Transaktionsmanager zu sein, der die Abläufe in Ihrem System kennt und die Rollbacks für Sie als Hintergrundprozess übernimmt, der sich über Ihr gesamtes System erstreckt (sodass die anderen Services angewiesen werden, einen Rollback durchzuführen) und wenn sie nicht erreichbar sind, benachrichtigen Sie sie später).

Gibt es eine andere akzeptierte Option? Beide scheinen ihre Nachteile zu haben. Der erste kann Deadlocks und eine Reihe anderer Probleme verursachen, der zweite kann zu Dateninkonsistenzen führen. Gibt es bessere Möglichkeiten?

88
Kristof

Der übliche Ansatz besteht darin, diese Mikrodienste so weit wie möglich zu isolieren - sie als einzelne Einheiten zu behandeln. Dann können Transaktionen im Kontext des gesamten Dienstes entwickelt werden (dh nicht Teil der üblichen DB-Transaktionen, obwohl Sie weiterhin dienstinterne DB-Transaktionen haben können).

Überlegen Sie, wie Transaktionen stattfinden und welche Art für Ihre Dienste sinnvoll ist. Sie können dann einen Rollback-Mechanismus implementieren, der den ursprünglichen Vorgang nicht ausführt, oder ein 2-Phasen-Festschreibungssystem, das den ursprünglichen Vorgang reserviert, bis Sie aufgefordert werden, einen tatsächlichen Festschreibungsvorgang durchzuführen. Natürlich bedeuten beide Systeme, dass Sie Ihre eigenen implementieren, aber dann implementieren Sie bereits Ihre Microservices.

Finanzdienstleistungen erledigen so etwas ständig - wenn ich Geld von meiner Bank zu Ihrer Bank transferieren möchte, gibt es keine einzige Transaktion, wie Sie sie in einer DB hätten. Sie wissen nicht, auf welchen Systemen eine der beiden Banken ausgeführt wird, und müssen diese daher effektiv wie Ihre Mikrodienste behandeln. In diesem Fall würde meine Bank mein Geld von meinem Konto auf ein Bestandskonto verschieben und Ihrer Bank dann mitteilen, dass sie etwas Geld haben. Wenn dieser Versand fehlschlägt, erstattet meine Bank mein Konto mit dem Geld, das sie zu senden versucht haben.

43
gbjbaanb

Ich denke, die Standardweisheit ist, dass Transaktionen niemals die Grenzen von Microservices überschreiten. Wenn ein bestimmter Datensatz wirklich atomar mit einem anderen übereinstimmen muss, gehören diese beiden Dinge zusammen.

Dies ist einer der Gründe, warum es sehr schwierig ist, ein System in Dienste aufzuteilen, bis Sie es vollständig entworfen haben. Was in der modernen Welt wahrscheinlich bedeutet, es geschrieben zu haben ...

31
soru

Ich denke, wenn Konsistenz eine starke Anforderung in Ihrer Anwendung ist, sollten Sie sich fragen, ob Microservices der bessere Ansatz ist. Wie Martin Fowler sagt :

Microservices führen zu möglichen Konsistenzproblemen, da sie lobenswert auf einer dezentralen Datenverwaltung bestehen. Mit einem Monolithen können Sie eine Reihe von Dingen in einer einzigen Transaktion zusammen aktualisieren. Für die Aktualisierung von Microservices sind mehrere Ressourcen erforderlich, und verteilte Transaktionen werden (aus gutem Grund) verpönt. Daher müssen Entwickler sich der Konsistenzprobleme bewusst sein und herausfinden, wie sie erkennen können, wenn die Dinge nicht synchron sind, bevor sie etwas tun, was der Code bereuen wird.

Aber vielleicht können Sie in Ihrem Fall die Konsistenz in Bezug auf die Verfügbarkeit opfern

Geschäftsprozesse sind oft toleranter gegenüber Inkonsistenzen als Sie denken, da Unternehmen die Verfügbarkeit häufig höher bewerten.

Ich frage mich aber auch, ob es eine Strategie für verteilte Transaktionen in Microservices gibt, aber vielleicht sind die Kosten zu hoch. Ich wollte Ihnen meine zwei Cent mit dem immer ausgezeichneten Artikel von Martin Fowler und dem Satz CAP geben.

17
gabrielgiussi

Wie in mindestens einer der Antworten hier, aber auch an anderer Stelle im Web vorgeschlagen, ist es möglich, einen Mikrodienst zu entwerfen, der Entitäten innerhalb einer normalen Transaktion zusammenhält, wenn Sie Konsistenz zwischen den beiden Entitäten benötigen.

Gleichzeitig kann es jedoch vorkommen, dass die Entitäten tatsächlich nicht zum selben Microservice gehören, z. B. Verkaufsunterlagen und Auftragsunterlagen (wenn Sie etwas bestellen, um den Verkauf zu erfüllen). In solchen Fällen benötigen Sie möglicherweise eine Möglichkeit, um die Konsistenz zwischen den beiden Mikrodiensten sicherzustellen.

Traditionell verteilte Transaktionen wurden verwendet und funktionieren meiner Erfahrung nach gut, bis sie auf eine Größe skaliert werden, bei der das Sperren zum Problem wird. Sie können die Sperrung lockern, sodass wirklich nur die relevanten Ressourcen (z. B. der verkaufte Gegenstand) durch eine Statusänderung "gesperrt" werden. Hier wird es jedoch schwierig, weil Sie das Gebiet betreten, in dem Sie alle bauen müssen Logik, dies selbst zu tun, anstatt zu sagen, dass eine Datenbank dies für Sie erledigt.

Ich habe mit Unternehmen zusammengearbeitet, die sich auf den Weg gemacht haben, ein eigenes Transaktions-Framework für die Behandlung dieses komplexen Problems zu entwickeln, aber ich empfehle es nicht, da es teuer ist und Zeit braucht, um zu reifen.

Es gibt Produkte, die an Ihr System angeschraubt werden können und auf Konsistenz achten. Eine Geschäftsprozess-Engine ist ein gutes Beispiel und sie handhabt normalerweise Konsistenz eventuell und verwendet Kompensation. Andere Produkte funktionieren ähnlich. In der Regel erhalten Sie eine Softwareschicht in der Nähe der Clients, die sich mit Konsistenz und Transaktionen befasst und (Mikro-) Services aufruft, um die eigentliche Geschäftsverarbeitung durchzuführen . Ein solches Produkt ist ein generischer JCA-Connector, der mit Java EE-Lösungen (aus Gründen der Transparenz: Ich bin der Autor) verwendet werden kann. Siehe http://blog.maxant.co) .uk/pebble/2015/08/04/1438716480000.html für weitere Details und eine eingehendere Diskussion der hier aufgeworfenen Fragen.

Eine andere Möglichkeit, Transaktionen und Konsistenz zu verarbeiten, besteht darin, einen Aufruf eines Mikrodienstes in einen Aufruf einer Transaktion wie einer Nachrichtenwarteschlange zu verpacken. Nehmen Sie das Beispiel für Verkaufs-/Bestelldatensätze von oben - Sie können einfach den Verkaufsmikroservice eine Nachricht an das Bestellsystem senden lassen, das in derselben Transaktion festgeschrieben wird, die den Verkauf in die Datenbank schreibt. Das Ergebnis ist eine asynchrone Lösung, die sehr gut skaliert. Mit Technologien wie Web-Sockets können Sie sogar das Problem des Blockierens umgehen, das häufig mit der Skalierung asynchroner Lösungen zusammenhängt. Weitere Ideen zu solchen Mustern finden Sie in einem anderen meiner Artikel: http://blog.maxant.co.uk/pebble/2015/08/11/1439322480000.html .

Unabhängig davon, für welche Lösung Sie sich letztendlich entscheiden, ist es wichtig zu erkennen, dass nur ein kleiner Teil Ihres Systems Dinge schreibt, die konsistent sein müssen - der meiste Zugriff ist wahrscheinlich schreibgeschützt. Bauen Sie aus diesem Grund das Transaktionsmanagement nur in die relevanten Teile des Systems ein, damit es noch gut skaliert werden kann.

16
Ant Kutschera

Es gibt viele Lösungen, die mehr Kompromisse eingehen, als mir gefällt. Zugegeben, wenn Ihr Anwendungsfall komplex ist, z. B. das Verschieben von Geld zwischen verschiedenen Banken, sind möglicherweise angenehmere Alternativen unmöglich. Aber schauen wir uns an, was wir in dem allgemeinen Szenario tun können, in dem die Verwendung von Microservices unsere potenziellen Datenbanktransaktionen beeinträchtigt.

Option 1: Vermeiden Sie die Notwendigkeit von Transaktionen, wenn dies alles möglich ist

Offensichtlich und bereits erwähnt, aber ideal, wenn wir es schaffen. Gehörten die Komponenten tatsächlich zum selben Microservice? Oder können wir die Systeme so umgestalten, dass die Transaktion unnötig wird? Vielleicht ist das Akzeptieren von Nichttransaktionalität das günstigste Opfer.

Option 2: Verwenden Sie eine Warteschlange

Wenn genügend Sicherheit besteht, dass der andere Dienst erfolgreich ist, können wir ihn über eine Art Warteschlange aufrufen. Der Artikel in der Warteschlange wird erst später abgeholt, aber wir können sicherstellen, dass der Artikel in der Warteschlange steht.

Angenommen, wir möchten eine Entität einfügen und eine E-Mail als einzelne Transaktion senden. Anstatt den Mailserver anzurufen, stellen wir die E-Mail in eine Tabelle.

Begin transaction
Insert entity
Insert e-mail
Commit transaction

Ein klarer Nachteil ist, dass mehrere Microservices Zugriff auf dieselbe Tabelle benötigen.

Option 3: Führen Sie die externe Arbeit zuletzt kurz vor Abschluss der Transaktion aus

Dieser Ansatz beruht auf der Annahme, dass das Festschreiben der Transaktion sehr unwahrscheinlich ist.

Begin transaction
Insert entity
Insert another entity
Make external call
Commit transaction

Wenn die Abfragen fehlschlagen, hat der externe Anruf noch nicht stattgefunden. Wenn der externe Anruf fehlschlägt, wird die Transaktion niemals festgeschrieben.

Dieser Ansatz bringt die Einschränkungen mit sich, dass wir nur eins externen Aufruf tätigen können, und er muss zuletzt ausgeführt werden (d. H. Wir können das Ergebnis nicht in unseren Abfragen verwenden).

Option 4: Erstellen Sie Dinge in einem ausstehenden Zustand

Wie veröffentlicht hier , können mehrere Microservices verschiedene Komponenten erstellen, die sich jeweils in einem ausstehenden Zustand befinden und nicht transaktional sind.

Jede Validierung wird durchgeführt, aber nichts wird in einem endgültigen Zustand erstellt. Nachdem alles erfolgreich erstellt wurde, wird jede Komponente aktiviert. Normalerweise ist dieser Vorgang so einfach und die Wahrscheinlichkeit, dass etwas schief geht, ist so gering, dass wir es möglicherweise sogar vorziehen, die Aktivierung nicht transaktional durchzuführen.

Der größte Nachteil ist wahrscheinlich, dass wir das Vorhandensein ausstehender Posten berücksichtigen müssen. Bei jeder ausgewählten Abfrage muss berücksichtigt werden, ob ausstehende Daten enthalten sein sollen. Die meisten sollten es ignorieren. Und Updates sind eine ganz andere Geschichte.

Option 5: Lassen Sie den Microservice seine Abfrage teilen

Keine der anderen Optionen erledigt das für Sie? Dann lasst uns unorthodox.

Je nach Unternehmen kann dies inakzeptabel sein. Es ist mir bewusst. Das ist unorthodox. Wenn es nicht akzeptabel ist, gehen Sie einen anderen Weg. Aber wenn dies zu Ihrer Situation passt, löst es das Problem einfach und kraftvoll. Es könnte der akzeptabelste Kompromiss sein.

Es gibt eine Möglichkeit, Abfragen von mehreren Mikrodiensten in eine einfache, einzelne Datenbanktransaktion umzuwandeln.

Gibt die Abfrage zurück, anstatt sie auszuführen.

Begin transaction
Execute our own query
Make external call, receiving a query
Execute received query
Commit transaction

In Bezug auf das Netzwerk muss jeder Mikrodienst auf jede Datenbank zugreifen können. Beachten Sie dies auch im Hinblick auf die zukünftige Skalierung.

Wenn sich die an der Transaktion beteiligten Datenbanken auf demselben Server befinden, handelt es sich um eine reguläre Transaktion. Wenn sie sich auf verschiedenen Servern befinden, handelt es sich um eine verteilte Transaktion. Der Code ist unabhängig davon der gleiche.

Wir erhalten die Abfrage, einschließlich des Verbindungstyps, der Parameter und der Verbindungszeichenfolge. Wir können es in eine ordentliche ausführbare Befehlsklasse packen und den Ablauf lesbar halten: Der Microservice-Aufruf führt zu einem Befehl, den wir als Teil unserer Transaktion ausführen.

Die Verbindungszeichenfolge ist das, was der ursprüngliche Mikrodienst uns gibt. Daher wird die Abfrage in jeder Hinsicht immer noch als von diesem Mikrodienst ausgeführt betrachtet. Wir leiten es nur physisch über den Client-Microservice weiter. Macht das einen Unterschied? Nun, damit können wir es mit einer anderen Abfrage in dieselbe Transaktion einfügen.

Wenn der Kompromiss akzeptabel ist, bietet dieser Ansatz die unkomplizierte Transaktionsfähigkeit einer Monolithanwendung in einer Microservice-Architektur.

2
Timo

In Microservices gibt es drei Möglichkeiten, um die Konsistenz zwischen diff zu erreichen. Dienstleistungen:

  1. Orchestrierung - Ein Prozess, der die Transaktion und das Rollback zwischen Diensten verwaltet.

  2. Choreografie - Der Dienst leitet Nachrichten untereinander weiter und erreicht schließlich einen konsistenten Zustand.

  3. Hybrid - Mischen der beiden oben genannten.

Eine vollständige Lektüre finden Sie unter folgendem Link: https://medium.com/capital-one-developers/microservices-when-to-react-vs-orchestrate-c6b18308a14c

1
techagrammer

Ich würde mit der Zerlegung des Problemraums beginnen - Identifizierung Ihrer Servicegrenzen . Wenn dies richtig gemacht wird, müssen Sie niemals dienstübergreifende Transaktionen durchführen.

Verschiedene Dienste haben ihre eigenen Daten, Verhaltensweisen, Motivationskräfte, Behörden, Geschäftsregeln usw. Ein guter Anfang besteht darin, aufzulisten, über welche Funktionen Ihr Unternehmen auf hoher Ebene verfügt. Zum Beispiel Marketing, Vertrieb, Buchhaltung, Support. Ein weiterer Ausgangspunkt ist die Organisationsstruktur. Beachten Sie jedoch, dass es eine Einschränkung gibt - aus bestimmten Gründen (z. B. politisch) ist dies möglicherweise nicht das optimale Schema für die Zerlegung von Unternehmen. Ein strengerer Ansatz ist Wertschöpfungskettenanalyse . Denken Sie daran, dass Ihre Dienste auch Personen umfassen können. Es handelt sich nicht ausschließlich um Software. Die Dienste sollten über Ereignisse miteinander kommunizieren.

Der nächste Schritt besteht darin, diese Dienste zu schnitzen. Als Ergebnis erhalten Sie immer noch relativ unabhängig Aggregate . Sie repräsentieren eine Einheit der Konsistenz. Mit anderen Worten, ihre Interna sollten konsistent und SÄURE sein. Aggregate kommunizieren auch über Ereignisse miteinander.

Wenn Sie der Meinung sind, dass Ihre Domain zuerst Konsistenz erfordert, denken Sie noch einmal darüber nach. Keines der großen und geschäftskritischen Systeme ist in diesem Sinne gebaut. Sie sind alle verteilt und schließlich konsistent. Überprüfen Sie Pat Hellands klassisches Papier .

hier sind einige praktische Tipps zum Aufbau eines verteilten Systems.

0
Zapadlo