Logischer Decodierungstext des zweiphasigen Commits in PostgreSQL 14

Aktualisierung: 2. Juli 2023

Logischer Decodierungstext des zweiphasigen Commits in PostgreSQL 14

Das Fujitsu OSS-Team und die PostgreSQL-Open-Source-Community haben zusammengearbeitet, um die Funktion zum Entschlüsseln des zweiphasigen Commits in der logischen Replikation in PG14 hinzuzufügen. Werfen wir einen Blick darauf, was diese Funktion ist?

Hintergrund

Beim Two-Phase-Commit handelt es sich um einen Mechanismus, bei dem Transaktionen in zwei Phasen festgeschrieben werden. Wird normalerweise in verteilten Datenbanken verwendet, um die Konsistenz sicherzustellen. Die beiden Phasen der Transaktion sind die PREPARE-Phase und die COMMIT/ROLLBACK-Phase. Die in PG in zwei Phasen übermittelten Befehle sind:

TRANSAKTION VORBEREITEN

COMMIT VORBEREITET

ROLLBACK VORBEREITET

PG unterstützt bereits in Version 8.0 das zweiphasige Commit, und Version 10.0 unterstützt die logische Replikation. Allerdings wurde das zweiphasige Commit bei der logischen Replikation nie unterstützt. Die Befehle PREPARE TRANSACTION, COMMIT PREPARED und ROLLBACK PREPARED wurden in einer einzigen Instanz unterstützt. Wenn diese Befehle jedoch logisch auf den Standby-Computer kopiert werden müssen, behalten sie nicht mehr ihre ursprüngliche Bedeutung bei. Der Befehl PREPARE TRANSACTION wird als NOP behandelt und überhaupt nicht dekodiert. Der Befehl COMMIT PREPARED wird als COMMIT und der Befehl ROLLBACK PREPARED als ABORT betrachtet.

Was ist ein zweiphasiger Commit?

Zweiphasen-Commit ist ein atomares Commit-Protokoll, das dazu beiträgt, die Konsistenz zwischen verteilten Datenbanken aufrechtzuerhalten. Gewöhnliche Commits, die Atomizität innerhalb der Datenbank bereitstellen, reichen nicht aus, um Konsistenz für datenbankübergreifende Transaktionen bereitzustellen. Um dieses Problem zu veranschaulichen, geben wir ein Beispiel:

1) John hat 300$ auf Bank A

2) Mark hat 100$ in Bank B

3) John möchte 100$ an Mark überweisen

Während der Transaktion müssen Sie 100 $ von Bank A an Bank B abheben. Am Ende der Transaktion sollten es 200 $ sein. Wenn eine Transaktion während des Überweisungsvorgangs fehlschlägt, sollte der Kontostatus auf den Zustand vor Beginn der Überweisung zurückgesetzt werden. Die Transaktion kann aus verschiedenen Gründen fehlschlagen. Wenn eine Unterbrechung auftritt, bevor die Transaktion festgeschrieben wird, wird die Transaktion zurückgesetzt. Wenn in unserem Beispiel eine Unterbrechung auftritt, wenn Johns Konto abgezogen wird, sollte Johns Konto des Unterbrechungsports nicht reduziert werden. Auf diese Weise sorgt ein einfacher Commit für die Konsistenz innerhalb der Datenbank.

Aber wir betrachten eine solche Situation, das heißt, die Transaktion, die 100 $ von Johns Konto abzieht, ist in einer Übermittlung erfolgreich, aber die Transaktion, die 100 $ auf Marks Konto bei Bank B hinzufügt, schlägt fehl und wird zurückgesetzt. Nachdem dieser Vorgang abgeschlossen ist, erhält Mark den Betrag nicht, obwohl Johns Konto belastet wurde. 100 $ sind verschwunden. Bei verteilten Transaktionen kann ein einfacher Commit fehlschlagen.

Schrittweise Ausführung verteilter Transaktionen

Beim zweiphasigen Commit fungiert eine der Datenbanken als Koordinator verteilter Transaktionen.

Stufe

Eine Datenbank beginnt mit der Anwendung von Transaktionen und bereitet sie dann vor. Es sendet vorbereitete Transaktionen in Form von Vorbereitungsnachrichten an andere Datenbanken. Die zweite Datenbank erhält die Prepare-Nachricht und bereitet dann die Transaktion vor. Prepare beinhaltet Änderungen in der Transaktion, führt jedoch kein Commit durch. Die schmutzigen Daten werden zur Persistenz auf die Festplatte geschrieben. Sobald alle Datenbanken die Transaktion vorbereitet haben und alle Informationen zur Transaktion auf der Festplatte gespeichert sind, ist die Vorbereitungsphase abgeschlossen.

Stufe

Als nächstes startet der Arbiter die Commit-Phase. Wenn die zweite Datenbank die Transaktion aus irgendeinem Grund nicht vorbereiten kann, startet der Arbiter die Rollback-Phase. Je nachdem, ob die Vorbereitung erfolgreich war, wird die Transaktion daher entweder festgeschrieben oder zurückgesetzt. Eine Unterbrechung in der letzten Commit-Phase kann wiederhergestellt werden, da die erforderliche Vorbereitungstransaktion auf die Festplatte geschrieben wurde und erneut angewendet werden kann.

Das zweiphasige Commit bezieht sich nicht auf Einzelinstanzdatenbanken, ist jedoch relevant, wenn Daten über mehrere Datenbankinstanzen repliziert werden.

Es ist sehr wichtig, bei der logischen Replikation das zweiphasige Commit zu unterstützen.

Funktionsübersicht

Vor der PG14-Version wurden logische Replikationstransaktionen erst dekodiert und repliziert, nachdem die Transaktion festgeschrieben wurde. Dadurch soll vermieden werden, dass die Replikationstransaktion eventuell abgebrochen wird.

Transaktion bei Commit entschlüsseln

Die logische Replikation von PG14 unterstützt die Befehle PREPARE TRANSACTION, COMMIT PREPARED und ROOLBACK PREPARED. Wenn der Befehl PREPARE TRANSACTION dekodiert wird, wird die Transaktion dekodiert und kopiert. PREPARE TRANSACTION startet die Transaktionswiedergabe und -dekodierung, genau wie COMMIT in WAL SENDER.

Entschlüsselung der Transaktion während der Vorbereitung

Wir haben auch einen neuen Plug-In-Callback definiert, um logische Decodierungs-Plug-Ins zu ermöglichen, um die zweiphasige Übermittlung zu unterstützen.

Rückruf

beschreiben

filternvorbereiten_cb

Erlauben Sie dem Plugin, Transaktionen zu filtern, die bei der Vorbereitung gemäß der im PREPARE TRANSACTION-Befehl verwendeten GID nicht dekodiert werden müssen

beginnen_vorbereiten_cb

Beginn der Transaktion vorbereiten

vorbereiten_cb

Wird aufgerufen, wenn der Befehl PREPARE TRANSACTION dekodiert wird

Commitvorbereitet_cb

Wird aufgerufen, wenn der Befehl COMMIT PREPARED dekodiert wird

Rollback_vorbereitet_cb

Wird aufgerufen, wenn der Befehl ROLLBACK PREPARED dekodiert wird

Plug-in-Modifikation

test_decodierung

Bei dem Plug-In handelt es sich um ein Ausgabe-Plug-In für die logische Dekodierung, das als Beispiel dienen soll, um Benutzern bei der Entwicklung ihres eigenen Plug-Ins für die logische Dekodierung zu helfen. test_decoding empfängt WAL über einen logischen Dekodierungsmechanismus und dekodiert es in eine Textdarstellung der durchgeführten Operation.

Es wurde modifiziert, um die neue zweistufige Callback-Funktion und die Dekodierung der Transaktion während der Vorbereitung verwenden zu können

APIs-Änderung

pg_logischen_Replikationsslot erstellen()

Die API fügt eine neue Option hinzu, um anzugeben, ob der Slot zweiphasiges Commit unterstützt. Das Ausgabe-Plugin kann einen Replikations-Slot mit einer Zwei-Phasen-Option verwenden, um Zwei-Phasen-Commit zu unterstützen.

pg_create_logical_replication_slot(slot_name name, plugin name [, temporär boolesch, zwei_phasig boolesch ] )

Fallstudie

Sehen wir uns an, wie Sie die decodierte Ausgabe der zweiphasigen Commit-Transaktion erkennen:

1) Erstellen Sie einen Replikations-Slot

Verwenden Sie test_decoding als Ausgabe-Plug-In und übergeben Sie true, damit der Slot die zweistufige Übermittlung und Dekodierung unterstützt.

postgres=# SELECT * FROM pg_Erstellen_logischer_Replikationssteckplatz('Regressionssteckplatz', 'Test_Decodierung',falsch,wahr);

Slot_name | lsn

Ich

Regressionsschlitz | 0/16B1970

(1 Reihe)

2) Erstellen Sie eine Tabelle

postgres=# CREATE TABLE data(id serieller Primärschlüssel, Datentext);

TABELLE ERSTELLEN

3) Ermitteln Sie den decodierten Ausgabeinhalt von Transaktion vorbereiten und Transaktion festschreiben

postgres=# BEGIN

postgres=*# INSERT INTO data(data) WERTE('5');

postgres=*# TRANSAKTION VORBEREITEN 'test_vorbereitet1';

postgres=# SELECT * FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL);

lsn | xid | Daten

Ich

0/1689DC0 529 BEGIN 529

0/1689DC0 | 529 Tabelle public.data: INSERT: id[integer]:3 data[text]:'5'

0/1689FC0 | 529 | TRANSAKTION VORBEREITEN 'test_vorbereitet1', txid 529

(3 Reihen)

postgres=# COMMIT VORBEREITET 'test_vorbereitet1';

postgres=# select * from pg_logical_slot_get_changes('regression_slot', NULL, NULL);

lsn | xid | Daten

Ich

0/168A060 | 529 | COMMIT VORBEREITEN 'test_vorbereitet1', txid 529

(4 Reihen)

postgres=# wähle * aus Daten;

ID | Daten

Ich

1 | 5

(1 Reihe)

Zukunft

Die Änderung von PG14 zu dieser Funktion verfügt über eine decodiererseitige Infrastruktur, die eine zweistufige Übermittlung der Decodierung während der Vorbereitung ermöglicht. Wir haben auch das test_decoding-Plugin modifiziert, um diese Infrastruktur zu nutzen.

Der nächste Schritt besteht darin, die zweistufige Unterstützung für das größte logische Decodierungs-Plug-in in PG zu implementieren – das pgoutput-Plug-in. Dieses Plug-In unterstützt den PUBLISHER/SUBSCRIBER-Modus der logischen Replikation. Es ist das am häufigsten verwendete Plug-In in der logischen Replikation. Das Fujitsu OSS-Team arbeitet mit der Open-Source-Community zusammen, um diese Funktion zu PG15 hinzuzufügen.

Für die zweiphasige Transaktion in der verteilten Datenbank muss PG auch unterstützen: Die Standby-Maschine informiert den Host über den Ausfall von PREPARE und leitet einen Rollback ein. Dieser Feedback-Mechanismus wird in PG nicht unterstützt und ist eine der Richtungen für zukünftige Verbesserungen.

  Links:

6mbi25l-120

rm500uz-2h