Sieben Lösungen für klassische verteilte Transaktionen zwischen MySQL und Golan

Sieben Lösungen für klassische verteilte Transaktionen zwischen MySQL und Golan

Vorwort:

Mit der rasanten Entwicklung der Geschäftswelt und ihrer zunehmenden Komplexität werden die Systeme fast aller Unternehmen von monolithischen zu verteilten Systemen wechseln, insbesondere zu einer Mikroservice-Architektur. Dann werden wir unweigerlich auf das Problem verteilter Transaktionen stoßen.
In diesem Artikel werden zunächst die relevanten grundlegenden Theorien vorgestellt, dann werden die klassischsten Transaktionslösungen zusammengefasst und schließlich Lösungen für die nicht ordnungsgemäße Ausführung von Untertransaktionen (Idempotenz, leere Kompensation und Aussetzungsprobleme) bereitgestellt, um sie mit allen zu teilen.

1. Grundlegende Theorie

Bevor wir die konkrete Lösung erläutern, wollen wir uns zunächst mit den theoretischen Grundlagen verteilter Transaktionen befassen.

Nehmen wir als Beispiel eine Geldüberweisung. Wenn A 100 Yuan an B überweisen muss, muss der Saldo von A -100 Yuan und der von B +100 Yuan betragen. Die gesamte Überweisung muss sicherstellen, dass A-100 und B+100 gleichzeitig erfolgreich sind oder gleichzeitig fehlschlagen. Sehen wir uns an, wie dieses Problem in verschiedenen Szenarien gelöst werden kann.

1.1 Transaktionen

Die Funktion, mehrere Anweisungen als Ganzes zu verarbeiten, wird als Datenbanktransaktion bezeichnet. Durch eine Datenbanktransaktion kann sichergestellt werden, dass alle Vorgänge im Rahmen der Transaktion erfolgreich sein oder fehlschlagen können.

Transaktionen haben vier Eigenschaften:原子性,一致性,隔離性und持久性. Diese vier Eigenschaften werden oft als ACID-Eigenschaften bezeichnet.

  • Atomicity : Alle Vorgänge in einer Transaktion sind entweder abgeschlossen oder überhaupt nicht abgeschlossen und enden nicht in einem Zwischenstadium. Tritt während der Ausführung einer Transaktion ein Fehler auf, wird der Zustand vor Beginn der Transaktion wiederhergestellt, als wäre die Transaktion nie ausgeführt worden.
  • Consistency : Die Integrität der Datenbank wird vor Beginn und nach Ende einer Transaktion nicht beeinträchtigt. Die Integrität, einschließlich Fremdschlüsseleinschränkungen und anwendungsdefinierter Einschränkungen, wird nicht verletzt.
  • Isolation : Die Fähigkeit einer Datenbank, mehrere gleichzeitige Transaktionen zum gleichzeitigen Lesen, Schreiben und Ändern ihrer Daten zuzulassen. Durch Isolation können Dateninkonsistenzen durch Cross-Execution verhindert werden, wenn mehrere Transaktionen gleichzeitig ausgeführt werden.
  • Durability : Nach Abschluss einer Transaktion sind Änderungen an den Daten dauerhaft und gehen auch bei einem Systemausfall nicht verloren.

Wenn unser Geschäftssystem nicht kompliziert ist und wir die Daten in einer Datenbank und einem Dienst ändern können, um die Übertragung abzuschließen, können wir Datenbanktransaktionen verwenden, um den korrekten Abschluss des Übertragungsgeschäfts sicherzustellen.

1.2 Verteilte Transaktionen

Das Interbanken-Überweisungsgeschäft ist ein typisches verteiltes Transaktionsszenario. Angenommen, A muss Geld zwischen Banken an B überweisen, dann sind die Daten zweier Banken betroffen. ACID der Überweisung kann nicht durch eine lokale Transaktion einer Datenbank garantiert werden und kann nur durch verteilte Transaktionen gelöst werden.

Eine verteilte Transaktion bedeutet, dass sich der Transaktionsinitiator, die Ressourcen und der Ressourcenmanager sowie der Transaktionskoordinator auf verschiedenen Knoten des verteilten Systems befinden. Im oben genannten Übertragungsvorgang befinden sich die Operationen des Benutzers A-100 und des Benutzers B+100 nicht auf demselben Knoten. Im Wesentlichen dienen verteilte Transaktionen dazu, die korrekte Ausführung von Datenoperationen in verteilten Szenarien sicherzustellen.

Um in einer verteilten Umgebung und bei verteilten Transaktionen die Anforderungen an Verfügbarkeit, Leistung und Leistungsminderung bei Diensten zu erfüllen und die Anforderungen an Konsistenz und Isolation zu reduzieren, muss einerseits die BASE-Theorie befolgt werden (BASE-bezogene Theorien beinhalten viel Inhalt, interessierte Studierende können sich auf die BASE-Theorie beziehen):

  • Basic Availability
  • Soft state
  • Eventual consistency

Ebenso folgen verteilte Transaktionen teilweise der ACID-Spezifikation:

  • Atomizität: Streng befolgen
  • Konsistenz: Die Konsistenz nach Abschluss der Transaktion wird strikt eingehalten; die Konsistenz während der Transaktion kann entsprechend gelockert werden
  • Isolation: Parallele Transaktionen können sich nicht gegenseitig beeinflussen; die Sichtbarkeit von Zwischenergebnissen der Transaktionen ermöglicht eine sichere Entspannung
  • Persistenz: Strikte Befolgung

2. Verteilte Transaktionslösungen

Aufgrund der verteilten Transaktionslösung ist es unmöglich, vollständige ACID -Garantien zu erreichen, und es gibt keine perfekte Lösung, die alle Geschäftsprobleme lösen kann. Daher wird in tatsächlichen Anwendungen die am besten geeignete verteilte Transaktionslösung entsprechend den unterschiedlichen Merkmalen des Unternehmens ausgewählt.

2.1 Zweiphasiges Commit/XA

XA ist eine von X/Open Organisation vorgeschlagene verteilte Transaktionsspezifikation. Die XA-Spezifikation definiert hauptsächlich die Schnittstelle zwischen dem (globalen) Transaktionsmanager (TM) und dem (lokalen) Ressourcenmanager (RM). Lokale Datenbanken wie mysql spielen die Rolle des RM in XA

XA ist in zwei Phasen unterteilt:

  • Phase 1 ( prepare ): Alle beteiligten RMs bereiten die Ausführung von Transaktionen vor und sperren die erforderlichen Ressourcen. Wenn der Teilnehmer ready , meldet er sich bei TM.
  • Phase 2 ( commit/rollback ): Wenn der Transaktionsmanager (TM) bestätigt, dass alle Teilnehmer (RM) bereit sind, sendet er einen commit -Befehl an alle Teilnehmer.

Derzeit unterstützen die meisten gängigen Datenbanken XA-Transaktionen, darunter mysql , oracle , sqlserver und postgre

Eine XA-Transaktion besteht aus einem oder mehreren Ressourcenmanagern (RMs), einem Transaktionsmanager (TM) und einer pplicationProgram (Anwendungsprogramm).

Die drei Rollen RM, TM und AP stellen hierbei klassische Rollenaufteilungen dar, welche über nachfolgende Transaktionsmodi wie Saga und Tcc durchlaufen werden.

Am Beispiel der obigen Übertragung sieht das Sequenzdiagramm einer erfolgreich abgeschlossenen XA-Transaktion wie folgt aus:

Wenn ein Teilnehmer prepare nicht durchführt, benachrichtigt TM alle Teilnehmer, die prepare abgeschlossen haben, über den Rollback.

Die Merkmale von XA-Transaktionen sind:

  • Einfach zu verstehen, noch einfacher zu entwickeln
  • Die Ressource ist für längere Zeit gesperrt und die Parallelität ist gering

Wenn Leser XA , go -Sprache sowie PHP , Python , Java , C# , Node usw. weiter studieren möchten, können sie sich an DTM wenden.

2.2 SAGA

Saga ist eine in diesem Datenbankpapier sagas erwähnte Lösung. Die Kernidee besteht darin, eine lange Transaktion in mehrere lokale kurze Transaktionen aufzuteilen, die vom Saga-Transaktionskoordinator koordiniert werden. Wenn sie normal enden, werden sie normal abgeschlossen. Wenn ein Schritt fehlschlägt, wird der Kompensationsvorgang einmal in umgekehrter Reihenfolge aufgerufen.

Am Beispiel der obigen Übertragung sieht das Sequenzdiagramm einer erfolgreich abgeschlossenen SAGA-Transaktion wie folgt aus:

Sobald Saga die Phase Cancel erreicht, darf Cancel in der Geschäftslogik nicht mehr fehlschlagen. Wenn die Antwort aufgrund von Netzwerk- oder anderen temporären Fehlern nicht erfolgreich ist, versucht TM es so lange erneut, bis Cancel erfolgreich zurückgegeben wird.

Merkmale von Saga-Transaktionen:

  • Hohe Parallelität, keine Notwendigkeit, Ressourcen für längere Zeit zu sperren, wie bei XA-Transaktionen
  • Normalbetrieb und Kompensationsbetrieb müssen definiert werden. Der Entwicklungsaufwand ist größer als bei XA.
  • Die Konsistenz ist schwach ausgeprägt. Bei Überweisungen kann es vorkommen, dass Benutzer A das Geld bereits abgebucht hat, die Überweisung aber fehlschlägt.

SAGA Inhalt in diesem Dokument ist recht umfangreich und umfasst zwei Wiederherstellungsstrategien und die gleichzeitige Ausführung von Zweigstellentransaktionen. Unsere Diskussion hier umfasst nur die einfachste SAGA

SAGA ist auf viele Szenarien anwendbar, einschließlich langer Transaktionen und Geschäftsszenarien, die nicht auf Zwischenergebnisse reagieren.

Wenn Leser SAGA eingehender studieren möchten, können sie auf DTM zurückgreifen, das Beispiele für erfolgreiches und fehlgeschlagenes Rollback von SAGA sowie die Handhabung verschiedener Netzwerkausnahmen enthält.

2.3 TCC

Das Konzept von TCC (Try-Confirm-Cancel) wurde erstmals von Pat Helland in einem 2007 veröffentlichten Artikel mit dem Titel „Life beyond Distributed Transactions: an Apostate’s Opinion“ vorgeschlagen.

TCC ist in 3 Phasen unterteilt:

  • Try -Phase: Versuchen Sie die Ausführung, schließen Sie alle Geschäftsprüfungen ab (Konsistenz) und reservieren Sie die erforderlichen Geschäftsressourcen (Quasi-Isolation).
  • Confirm : Bestätigt die tatsächliche Ausführung des Geschäfts ohne jegliche Geschäftsprüfung. Es werden nur die in der Testphase reservierten Geschäftsressourcen verwendet. Der Confirm erfordert ein idempotentes Design und muss wiederholt werden, wenn Confirm fehlschlägt.
  • Cancel : Brechen Sie die Ausführung ab und geben Sie die in der Versuchsphase reservierten Geschäftsressourcen frei. Die Lösungen zur Ausnahmebehandlung in Cancel Abbruchphase sind grundsätzlich dieselben wie in der Confirm und erfordern ein idempotentes Design.

Am Beispiel der obigen Überweisung wird der Betrag normalerweise bei „Versuchen“ eingefroren, aber nicht abgezogen, bei Confirm abgezogen und bei „ Cancel freigegeben.

Das Zeitdiagramm einer erfolgreich abgeschlossenen TCC-Transaktion sieht wie folgt aus:

Confirm/Cancel von TCC darf keine Fehler in der Geschäftslogik zurückgeben. Wenn aufgrund von Netzwerk- oder anderen temporären Fehlern kein Erfolg zurückgegeben werden kann, versucht es TM so lange, bis Confirm/Cancel einen Erfolg zurückgibt.

Die Funktionen von TCC sind wie folgt:

  • Hohe Parallelität und keine langfristige Ressourcenbindung.
  • Der Entwicklungsaufwand ist groß und es muss Try/Confirm/Cancel -Schnittstelle bereitgestellt werden.
  • Die Konsistenz ist gut und es wird keine Situation geben, in der SAGA das Geld abgezogen hat, die Überweisung am Ende aber fehlschlägt.
  • TCC ist auf auftragsbasierte Unternehmen und Unternehmen mit Einschränkungen hinsichtlich Zwischenzuständen anwendbar.

Wenn Leser TCC weiter studieren möchten, können sie sich auf DTM beziehen

2.4 Lokale Nachrichtentabelle

Die Lösung mit der lokalen Nachrichtentabelle wurde ursprünglich vom ebay -Architekten Dan Pritchett in einem 2008 bei ACM veröffentlichten Artikel vorgeschlagen. Der Kern des Designs besteht darin, die asynchrone Ausführung von Aufgaben sicherzustellen, die eine verteilte Verarbeitung durch Nachrichten erfordern.

Der allgemeine Ablauf ist wie folgt:

Das Schreiben lokaler Nachrichten und Geschäftsvorgänge werden in einer Transaktion zusammengefasst, um die Atomizität von Geschäftsvorgängen und Nachrichtenversand sicherzustellen. Entweder sind sie alle erfolgreich, oder sie schlagen alle fehl.

Fehlertoleranzmechanismus:

  • Wenn die Saldenabzugstransaktion fehlschlägt, wird die Transaktion ohne weitere Schritte direkt rückgängig gemacht.
  • Bei Fehlern bei der Nachrichtenerstellung in der Round-Robin-Reihenfolge und bei Fehlern bei der Erhöhung des Saldos der Transaktionen wird ein erneuter Versuch durchgeführt.

Funktionen der lokalen Nachrichtentabelle:

  • Lange Transaktionen müssen nur in mehrere Aufgaben aufgeteilt werden, was einfach zu verwenden ist
  • Der Produzent muss eine zusätzliche Nachrichtentabelle erstellen
  • Jede lokale Nachrichtentabelle muss abgefragt werden
  • Wenn die Verbraucherlogik nicht erfolgreich wiederholt werden kann, sind weitere Mechanismen erforderlich, um den Vorgang rückgängig zu machen.

Gilt für Geschäfte, die asynchron ausgeführt werden können und für nachfolgende Vorgänge nicht zurückgesetzt werden müssen.

2.5 Transaktionsnachrichten

Bei der oben erwähnten Lösung mit lokaler Nachrichtentabelle muss der Produzent eine zusätzliche Nachrichtentabelle erstellen und außerdem die lokale Nachrichtentabelle abfragen, was eine große geschäftliche Belastung darstellt. Alibabas Open Source RocketMQ 4.3 und spätere Versionen unterstützen offiziell Transaktionsnachrichten. Transaktionsnachrichten platzieren im Wesentlichen die lokale Nachrichtentabelle auf RocketMQ , um das Atomizitätsproblem zwischen dem Senden von Nachrichten auf der Produktionsseite und der lokalen Transaktionsausführung zu lösen.

Senden und Übermitteln von Transaktionsnachrichten:

Nachricht senden (halbe Nachricht)
Der Server speichert die Nachricht und reagiert auf das Schreibergebnis der Nachricht, um lokale Transaktionen entsprechend dem Sendeergebnis auszuführen (wenn das Schreiben fehlschlägt, ist die half Nachricht für das Unternehmen nicht sichtbar und die lokale Logik wird nicht ausgeführt).
Führen Sie Commit oder Rollback entsprechend dem lokalen Transaktionsstatus aus ( Commit -Vorgang veröffentlicht Nachrichten, die für Verbraucher sichtbar sind).

Das normale Sendeflussdiagramm sieht wie folgt aus:

Ablauf der Entschädigung:

Für Transaktionsnachrichten ohne Commit/Rollback (Nachrichten im pending Zustand) wird eine „Überprüfung“ vom Server aus initiiert.
Der Produzent empfängt die Rückrufnachricht und gibt den Status der lokalen Transaktion zurück, die der Nachricht entspricht, nämlich Commit oder Rollback
Die Transaktionsnachrichtenlösung ist dem lokalen Nachrichtentabellenmechanismus sehr ähnlich. Der Hauptunterschied besteht darin, dass die ursprünglichen zugehörigen lokalen Tabellenoperationen durch eine umgekehrte Abfrageschnittstelle ersetzt werden.

Die Merkmale von Transaktionsnachrichten sind wie folgt:

  • Lange Transaktionen müssen lediglich in mehrere Aufgaben aufgeteilt werden. Zudem steht eine benutzerfreundliche Schnittstelle für umgekehrte Abfragen zur Verfügung.
  • Wenn die Verbraucherlogik nicht erfolgreich wiederholt werden kann, sind weitere Mechanismen erforderlich, um den Vorgang rückgängig zu machen.

Gilt für Geschäfte, die asynchron ausgeführt werden können und für nachfolgende Vorgänge nicht zurückgesetzt werden müssen.

2.6 Best-Efforts-Benachrichtigung

Der Initiator der Benachrichtigung verwendet einen bestimmten Mechanismus, um den Empfänger bestmöglich über die Ergebnisse der Geschäftsverarbeitung zu informieren. Dazu gehören insbesondere:

Es gibt einen bestimmten Benachrichtigungsmechanismus für Nachrichtenwiederholungen. Da der Empfänger der Benachrichtigung die Benachrichtigung möglicherweise nicht erhalten hat, muss ein bestimmter Mechanismus zur Wiederholung der Nachricht vorhanden sein.
Mechanismus zum Korrekturlesen von Nachrichten. Wenn der Empfänger trotz aller Bemühungen nicht benachrichtigt wird oder die Nachricht nach dem Konsumieren erneut konsumiert werden muss, kann der Empfänger die benachrichtigende Partei aktiv nach Nachrichteninformationen abfragen, um den Bedarf zu decken.
Die zuvor eingeführte lokale Nachrichtentabelle und die Transaktionsnachricht sind beide zuverlässige Nachrichten. Worin unterscheiden sie sich von der hier eingeführten Best-Effort-Benachrichtigung?

Zuverlässige Nachrichtenkonsistenz: Die Partei, die die Benachrichtigung initiiert, muss sicherstellen, dass die Nachricht gesendet und an die empfangende Benachrichtigungspartei gesendet wird. Die Zuverlässigkeit der Nachricht wird hauptsächlich von der Partei gewährleistet, die die Benachrichtigung initiiert.

Benachrichtigung mit bestmöglichem Aufwand: Der Initiator der Benachrichtigung bemüht sich nach besten Kräften, den Empfänger der Benachrichtigung über das Geschäftsverarbeitungsergebnis zu benachrichtigen, aber die Nachricht wird möglicherweise nicht empfangen. In diesem Fall muss der Empfänger der Benachrichtigung die Schnittstelle des Initiators aktiv aufrufen, um das Geschäftsverarbeitungsergebnis abzufragen. Die Zuverlässigkeit der Benachrichtigung hängt vom Empfänger der Benachrichtigung ab.

Im Hinblick auf Lösungen erfordert die Best-Effort-Benachrichtigung:

  • Bereitstellung einer Schnittstelle, damit der Benachrichtigungsempfänger die Geschäftsverarbeitungsergebnisse über die Schnittstelle abfragen kann
  • Der ACK -Mechanismus der Nachrichtenwarteschlange erhöht das Benachrichtigungsintervall schrittweise um 1min , 5min , 10min ., 30min ., 1h , 2h , 5h . und 10h , bis die Obergrenze des für die Benachrichtigung erforderlichen Zeitfensters erreicht ist. Keine weiteren Benachrichtigungen

Die Best-Effort-Benachrichtigung ist auf Geschäftsbenachrichtigungstypen anwendbar. Beispielsweise wird das Ergebnis einer WeChat-Transaktion jedem Händler durch eine Best-Effort-Benachrichtigung mitgeteilt. Es gibt Rückrufbenachrichtigungen und Transaktionsabfrageschnittstellen.

2.7 AT-Transaktionsmodus

Dies ist ein Transaktionsmodus im Open-Source-Projekt Seata von Alibaba, in Ant Financial auch als FMT bekannt. Der Vorteil besteht darin, dass der Transaktionsmodus ähnlich wie der XA-Modus verwendet wird. Das Unternehmen muss nicht verschiedene Kompensationsvorgänge schreiben, und das Rollback wird automatisch vom Framework abgeschlossen. Der Nachteil ist ebenfalls ähnlich wie bei XA, da es lange Sperren gibt und daher nicht für Szenarien mit hoher Parallelität geeignet ist. Aus Leistungssicht ist der AT-Modus besser als XA, bringt aber auch neue Probleme mit sich, wie beispielsweise Dirty Rollback.

3. Ausnahmebehandlung

In jedem Link verteilter Transaktionen können Netzwerk- und Geschäftsfehler auftreten. Diese Probleme erfordern, dass die Geschäftspartei verteilter Transaktionen drei Funktionen implementiert: Anti-Air-Rollback, Idempotenz und Anti-Hanging.

3.1 Ungewöhnliche Situationen

Im Folgenden werden diese Ausnahmen anhand von TCC-Transaktionen veranschaulicht:

Leeres Rollback:

Wenn die Cancel-Methode der zweiten Stufe aufgerufen wird, ohne die Try-Methode der TCC-Ressource aufzurufen, muss die Cancel-Methode erkennen, dass dies ein leeres Rollback ist, und direkt „Erfolg“ zurückgeben.

Der Grund hierfür ist, dass bei einer Zweigstellentransaktion, die sich in einer Dienstausfallzeit oder Netzwerkanomalie befindet, der Aufruf der Zweigstellentransaktion als fehlgeschlagen aufgezeichnet wird. Zu diesem Zeitpunkt wird die Try-Phase nicht ausgeführt. Wenn der Fehler behoben ist, wird die verteilte Transaktion zurückgesetzt und die Cancel-Methode der zweiten Phase aufgerufen, was zu einem leeren Rollback führt.

Idempotenz:

Da jede Anfrage zu Netzwerkanomalien und doppelten Anfragen führen kann, müssen alle verteilten Transaktionszweige Idempotenz sicherstellen.

Suspension:

Suspendierung bedeutet, dass bei einer verteilten Transaktion die Cancel -Schnittstelle der zweiten Stufe vor der Try-Schnittstelle ausgeführt wird.

Der Grund hierfür ist, dass beim Aufrufen der Verzweigungstransaktion durch RPC zuerst die Verzweigungstransaktion registriert und dann der RPC-Aufruf ausgeführt wird. Wenn das Netzwerk für den RPC-Aufruf zu diesem Zeitpunkt überlastet ist, benachrichtigt TM RM nach dem RPC-Timeout, die verteilte Transaktion zurückzusetzen. Es ist möglich, dass die RPC-Anforderung von Try nach Abschluss des Rollbacks den Teilnehmer zur tatsächlichen Ausführung erreicht.

Werfen wir einen Blick auf ein Zeitdiagramm von Netzwerkanomalien, um die oben genannten Probleme besser zu verstehen.

  • Wenn der Geschäftsprozess Anforderung 4 ist, wird Cancel vor Versuch ausgeführt und ein leerer Rollback muss verarbeitet werden
  • Wenn der Geschäftsprozess 6 anfordert, wird Cancel wiederholt ausgeführt, was Idempotenz erfordert
  • Wenn das Geschäft 8 anfordert, wird Try nach Cancel ausgeführt und muss die Aussetzung verarbeiten

Angesichts der oben genannten komplexen Netzwerkanomalien bestehen die derzeit von verschiedenen Unternehmen empfohlenen Lösungen darin, dass die Geschäftspartei einen eindeutigen Schlüssel verwendet, um abzufragen, ob die zugehörigen Vorgänge abgeschlossen wurden, und bei Abschluss direkt eine Erfolgsmeldung zurückgibt. Die entsprechende Beurteilungslogik ist komplex, fehleranfällig und stellt eine erhebliche geschäftliche Belastung dar.

3.2 Teiltransaktionsbarriere

Im Projekt https://github.com/yedf/dtm ist eine Sub-Transaktionsbarriere-Technologie entstanden. Mit dieser Technologie kann dieser Effekt erzielt werden. Siehe das schematische Diagramm:

Alle diese Anfragen werden beim Erreichen der Subtransaktionsbarriere herausgefiltert, wenn sie abnormal sind, und passieren die Barriere, wenn sie normal sind. Nachdem Entwickler Subtransaktionsbarrieren verwendet haben, werden alle oben genannten Ausnahmen ordnungsgemäß behandelt. Geschäftsentwickler müssen sich nur auf die eigentliche Geschäftslogik konzentrieren, was ihre Belastung erheblich reduziert.

Die Subtransaktionsbarriere stellt eine Methode namens ThroughBarrierCall bereit, deren Prototyp lautet:

Funktion ThroughBarrierCall(db *sql.DB, transInfo *TransInfo, busiCall BusiFunc)

Geschäftsentwickler schreiben ihre eigene zugehörige Logik in busiCall und rufen diese Funktion auf. ThroughBarrierCall stellt sicher, dass busiCall in Szenarien wie leerem Rollback und Suspendierung nicht aufgerufen wird. Wenn das Geschäft wiederholt aufgerufen wird, gibt es eine idempotente Kontrolle, um sicherzustellen, dass es nur einmal übermittelt wird.

Subtransaktionsbarrieren verwalten TCC, SAGA, Transaktionsnachrichten usw. und können auch auf andere Bereiche erweitert werden

3.3 Subtransaktionsbarriereprinzip

Das Prinzip der Subtransaktionsbarrieretechnologie besteht darin, in der lokalen Datenbank eine Branch-Transaktionsstatustabelle sub_trans_barrier einzurichten, wobei der eindeutige Schlüssel die globale Transaktions-ID-Subtransaktions-ID-Subtransaktions-Branchname ist ( try|confirm|cancel ).

  • Offene Transaktion
  • Wenn es sich um einen Try-Zweig handelt, werden beim Einfügen die Einfügungen gid-branchid-try insert ignore . Wenn das Einfügen erfolgreich ist, wird die Logik innerhalb der Barriere aufgerufen.
  • Wenn es sich um einen Bestätigungszweig handelt, insert ignore die Einfügungen gid-branchid-confirm . Wenn die Einfügung erfolgreich ist, wird die Logik innerhalb der Barriere aufgerufen.
  • Wenn es sich um einen Cancel-Zweig handelt, insert ignore gid-branchid-try und fügt dann gid-branchid-cancel ein. Wenn try nicht eingefügt wird und cancel erfolgreich eingefügt wurde, wird die Logik innerhalb der Barriere aufgerufen
  • Die Logik innerhalb der Barriere gibt Erfolg zurück, die Transaktion wird festgeschrieben und Erfolg wird zurückgegeben
  • Die Logik innerhalb der Barriere gibt einen Fehler zurück, setzt die Transaktion zurück und gibt einen Fehler zurück.

Mit diesem Mechanismus werden Probleme im Zusammenhang mit Netzwerkanomalien gelöst

  • Leere Kompensationskontrolle - wenn Try nicht ausgeführt wird und Cancel direkt ausgeführt wird, dann ist das Einfügen von Cancel in gid-branchid-try erfolgreich, ohne die Logik innerhalb der Barriere zu durchlaufen, wodurch die leere Kompensationskontrolle sichergestellt wird.
  • Idempotenz-Kontrolle - kein Zweig kann einen eindeutigen Schlüssel wiederholt einfügen, wodurch sichergestellt wird, dass es nicht zu einer wiederholten Ausführung kommt
  • Anti-Hängekontrolle - Der Versuch wird nach dem Abbrechen ausgeführt. Wenn also der eingefügte gid-branchid-try nicht erfolgreich ist, wird er nicht ausgeführt, wodurch die Anti-Hängekontrolle gewährleistet wird

Bei SAGA, Transaktionsnachrichten usw. ist der Mechanismus ähnlich.

3.4 Zusammenfassung der Teiltransaktionsbarrieren

Die Subtransaktionsbarriere-Technologie wurde erstmals von https://github.com/yedf/dtm entwickelt. Ihre Bedeutung liegt in der Entwicklung eines einfachen und leicht zu implementierenden Algorithmus und der Bereitstellung einer einfachen und leicht zu bedienenden Schnittstelle. Mithilfe dieser beiden Elemente sind Entwickler vollständig von der Handhabung von Netzwerkausnahmen befreit.

Diese Technologie muss derzeit mit dem Transaktionsmanager yedf/dtm verwendet werden. Das SDK ist derzeit für Entwickler der Sprachen Go und Python verfügbar. SDKs für weitere Sprachen sind in Planung. Für andere verteilte Transaktionsframeworks kann die Technologie gemäß den oben genannten Prinzipien schnell implementiert werden, solange entsprechende verteilte Transaktionsinformationen bereitgestellt werden.

4. Praxis der verteilten Transaktionen

Wir nehmen die zuvor vorgestellte SAGA-Transaktion als Beispiel und verwenden DTM als Transaktionsrahmen, um eine bestimmte verteilte Transaktion abzuschließen. In diesem Beispiel wird die Sprache Go verwendet. Wenn dich das nicht interessiert, kannst du direkt zur Zusammenfassung am Ende des Artikels springen.

4.1 Eine SAGA-Transaktion

Schreiben wir zunächst den Kerngeschäftscode, um den Kontostand des Benutzers anzupassen

Funktion qsAdjustBalance(uid int, Betrag int) (Schnittstelle{}, Fehler) {
    _, err := dtmcli.SdbExec(sdbGet(), "aktualisiere dtm_busi.user_account, setze Guthaben = Guthaben + ? wobei user_id = ?", Betrag, uid)
    returniere dtmcli.ResultSuccess, err
}


Als nächstes schreiben wir eine spezifische Verarbeitungsfunktion für Vorwärtsoperationen/Kompensationsoperationen

    app.POST(qsBusiAPI+"/TransIn", common.WrapHandler(func(c *gin.Context) (Schnittstelle{}, Fehler) {
        Rückgabewert qsAdjustBalance(2, 30)
    }))
    app.POST(qsBusiAPI+"/TransInCompensate", common.WrapHandler(func(c *gin.Context) (Schnittstelle{}, Fehler) {
        gibt qsAdjustBalance(2, -30) zurück
    }))
    app.POST(qsBusiAPI+"/TransOut", common.WrapHandler(func(c *gin.Context) (Schnittstelle{}, Fehler) {
        gibt qsAdjustBalance(1, -30) zurück
    }))
    app.POST(qsBusiAPI+"/TransOutCompensate", common.WrapHandler(func(c *gin.Context) (Schnittstelle{}, Fehler) {
        Rückgabewert qsAdjustBalance(1, 30)
    }))

Zu diesem Zeitpunkt waren die Verarbeitungsfunktionen jeder Untertransaktion in Ordnung. Anschließend wird die SAGA-Transaktion geöffnet, um Zweigstellenaufrufe durchzuführen.

    req := &gin.H{"amount": 30} // Microservice-Nutzlast // DtmServer ist die Adresse der DTM-Dienst-Saga := dtmcli.NewSaga(DtmServer, dtmcli.MustGenGid(DtmServer)).
        // Fügen Sie eine TransOut-Untertransaktion hinzu. Die Vorwärtsoperation ist url: qsBusi+"/TransOut", und die Rückwärtsoperation ist url: qsBusi+"/TransOutCompensate"
        Hinzufügen(qsBusi+"/TransOut", qsBusi+"/TransOutCompensate", erforderlich).
        // Fügen Sie eine TransIn-Untertransaktion hinzu. Die Vorwärtsoperation ist url: qsBusi+"/TransOut", und die Rückwärtsoperation ist url: qsBusi+"/TransInCompensate"
        Hinzufügen(qsBusi+"/TransIn", qsBusi+"/TransInCompensate", erforderlich)
    //Senden Sie die Saga-Transaktion, DTM wird alle Untertransaktionen abschließen/alle Untertransaktionen zurücksetzen err := saga.Submit()

An diesem Punkt wurde eine vollständige verteilte SAGA-Transaktion geschrieben.

Wenn Sie ein erfolgreiches Beispiel vollständig ausführen möchten, richten Sie die Umgebung gemäß den Anweisungen des yedf/dtm-Projekts ein und führen Sie das Saga-Beispiel mit dem folgenden Befehl aus:

führe app/main.go quick_start aus

4.2 Umgang mit Netzwerkanomalien

Was soll ich tun, wenn beim Aufrufen der Übertragungsoperation in einer an dtm übermittelten Transaktion ein kurzer Fehler auftritt? Gemäß dem SAGA-Transaktionsprotokoll wird dtm nicht abgeschlossene Vorgänge wiederholen. Was sollten wir jetzt tun? Der Fehler kann ein Netzwerkfehler nach Abschluss des Übertragungsvorgangs sein oder es kann vorkommen, dass der Computer während des Übertragungsvorgangs abstürzt. Wie können wir sicherstellen, dass die Anpassung des Kontostands korrekt ist?

Wir verwenden die Subtransaktionsbarrierefunktion, um sicherzustellen, dass nach mehreren Wiederholungsversuchen nur eine erfolgreiche Übermittlung erfolgt.

Wir passen die Verarbeitungsfunktion an:

Funktion sagaBarrierAdjustBalance(sdb *sql.Tx, uid int, amount int) (Schnittstelle{}, Fehler) {
    _, err := dtmcli.StxExec(sdb, "aktualisiere dtm_busi.user_account, setze Guthaben = Guthaben + ? wobei Benutzer-ID = ?", Betrag, UID)
    returniere dtmcli.ResultSuccess, err

}

Funktion sagaBarrierTransIn(c *gin.Context) (Schnittstelle{}, Fehler) {
    return dtmcli.ThroughBarrierCall(sdbGet(), MustGetTrans(c), func(sdb *sql.Tx) (Schnittstelle{}, Fehler) {
        gibt sagaBarrierAdjustBalance(sdb, 1, reqFrom(c).Betrag) zurück
    })
}

Funktion sagaBarrierTransInCompensate(c *gin.Context) (Schnittstelle{}, Fehler) {
    return dtmcli.ThroughBarrierCall(sdbGet(), MustGetTrans(c), func(sdb *sql.Tx) (Schnittstelle{}, Fehler) {
        gibt sagaBarrierAdjustBalance(sdb, 1, -reqFrom(c).Betrag) zurück
    })
}

Der Aufruf dtmcli.TroughBarrierCall verwendet hier die Sub-Transaction-Barrier-Technologie, um sicherzustellen, dass die Rückruffunktion im dritten Parameter nur einmal verarbeitet wird.

Sie können mehrmals versuchen, diesen TransIn-Dienst anzurufen, und der Saldo wird nur einmal angepasst. Sie können den neuen Prozess ausführen, indem Sie den folgenden Befehl ausführen:

go run app/main.go saga_barrier

4.3 Rollback-Behandlung

Was passiert, wenn die Bank bei der Vorbereitung der Überweisung des Betrags an Benutzer 2 eine Anomalie auf dem Konto von Benutzer 2 feststellt und eine Fehlermeldung meldet? Wir passen die Verarbeitungsfunktion so an, dass der Übertragungsvorgang einen Fehler zurückgibt

Funktion sagaBarrierTransIn(c *gin.Context) (Schnittstelle{}, Fehler) {
    returniere dtmcli.ResultFailure, nil
}

Wir geben ein Zeitdiagramm der Interaktion zwischen Transaktionsfehlern

Hier gibt es eine Sache. Der Vorwärtsvorgang von TransIn hat nichts bewirkt und einen Fehler zurückgegeben. Führt der Aufruf des Kompensationsvorgangs von TransIn zu diesem Zeitpunkt dazu, dass die Rückwärtsanpassung fehlschlägt?

Keine Sorge. Die vorherige Subtransaktionsbarrieretechnologie kann sicherstellen, dass die Kompensation ein No-Op ist, wenn TransIn Fehler vor der Übermittlung auftritt. Wenn der TransIn Fehler nach der Übermittlung auftritt, übermittelt der Kompensationsvorgang die Daten einmal. Wenn TransIn noch ausgeführt wird, wartet der Kompensationsvorgang auf die endgültige Übermittlung/das endgültige Rollback von TransIn, bevor er die Kompensation/das leere Rollback übermittelt.

Sie können das TransIn, das einen Fehler zurückgibt, wie folgt ändern:

Funktion sagaBarrierTransIn(c *gin.Context) (Schnittstelle{}, Fehler) {
    dtmcli.ThroughBarrierCall(sdbGet(), MustGetTrans(c), Funktion(sdb *sql.Tx) (Schnittstelle{}, Fehler) {
        Rückgabewert für sagaBarrierAdjustBalance(sdb, 1, 30)
    })
    returniere dtmcli.ResultFailure, nil
}

Das Endergebnis ist, dass die Bilanz immer noch in Ordnung ist

5. Zusammenfassung

Dieser Artikel stellt einige grundlegende Theorien zu verteilten Transaktionen vor und erläutert häufig verwendete Lösungen für verteilte Transaktionen. Die zweite Hälfte des Artikels enthält außerdem die Ursachen, Klassifizierungen und eleganten Lösungen für Transaktionsausnahmen. Abschließend wird ein ausführbares Beispiel für verteilte Transaktionen verwendet, um den zuvor eingeführten Inhalt in einem kurzen Programm zu demonstrieren.

Dies ist das Ende dieses Artikels über die sieben klassischen Lösungen für verteilte MySQL- und Golan-Transaktionen. Weitere Informationen zu den sieben klassischen Lösungen für verteilte Transaktionen finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, Sie werden 123WORDPRESS.COM auch in Zukunft unterstützen!

Das könnte Sie auch interessieren:
  • So implementieren Sie verteilte Transaktionen in MySQL XA
  • Implementierung der Knotenverbindung zur MySQL-Abfragetransaktionsverarbeitung
  • Beispiel-Tutorial für MySQL-Datenbanktransaktionen
  • Analyse und Zusammenfassung der Auswirkungen von MySQL-Transaktionen auf die Effizienz
  • Details zur MySQL-Transaktionsisolationsebene
  • Detaillierte Erklärung der Transaktionen und Indizes in der MySQL-Datenbank
  • MySQL-Transaktionsanalyse

<<:  Vue implementiert Beispielcode für benutzerdefinierte „modales Popup-Fenster“-Komponente

>>:  Lösung für das Problem, dass der Rahmenstil des Tags <td></td> im Browser nicht angezeigt werden kann

Artikel empfehlen

Installieren Sie mehrere PHP-Versionen für Nginx unter Linux

Wenn wir die LNPM-Serverumgebung installieren und...

MySQL: Datenintegrität

Die Datenintegrität wird in Entitätsintegrität, D...

Stabile Version von MySQL 8.0.18 veröffentlicht! Hash Join ist wie erwartet da

Die stabile Version (GA) von MySQL 8.0.18 wurde g...

30 hervorragende Beispiele für Farbabstimmung im Webdesign

Heute habe ich in diesem Artikel 30 hervorragende ...

Lösung für das Problem mit verstümmelten chinesischen MySQL-Zeichen

1. Die chinesischen verstümmelten Zeichen erschei...

Zusammenfassung verschiedener Methoden für Vue zum Erreichen dynamischer Stile

Inhaltsverzeichnis 1. Ternäres Operatorurteil 2. ...

Lernunterlagen zum Schreiben des ersten Vue-Programms

Inhaltsverzeichnis 1. Schreiben Sie ein HTML, das...

mysql installer community 8.0.12.0 grafische anleitung zur installation

Dieses Tutorial beschreibt die Installation der M...

So fragen Sie ab, ob die MySQL-Tabelle gesperrt ist

Spezifische Methode: (Empfohlenes Tutorial: Lern-...

Erstellen Sie mit Node.JS ein Echtzeit-Warnsystem für Unwetter

Inhaltsverzeichnis Vorwort: Schritt 1: Finden Sie...

Einen Web-Rechner mit Javascript schreiben

Dieser Artikel beschreibt hauptsächlich die Auswi...