PostgreSQL – Datenkonsistenzprobleme bei der logischen Replikation

Im Gegensatz zur physischen Replikation ist der Schreibzugriff auf den Teilnehmerknoten bei der logischen Replikation nicht deaktiviert. Dies bedeutet, dass DML- und DDL-Anweisungen wie INSERT, UPDATE, DELETE oder ALTER auf dem Abonnenten ausgeführt werden können. Da die Replikation jedoch unidirektional ist, werden diese Änderungen nicht zurück an den Herausgeber repliziert. Dieses Verhalten kann zu Problemen führen – die Replikation kann mit all ihren Konsequenzen gestoppt werden oder die Daten können nicht mehr synchron sein. In diesem Beitrag möchten wir einige Tipps zum Umgang mit solchen Problemen geben.
Zur Erinnerung können Sie hier noch einmal sehen, wie die Architektur der logischen Replikation umgesetzt ist.

Szenario 1:
Daten auf der Abonnentenseite einfügen

Daten können problemlos in eine Replikationszieltabelle eingefügt werden, vorausgesetzt, eine Zeile mit identischer REPLICA-IDENTITÄT wird anschließend nicht auf dem Herausgeberknoten eingefügt. Betrachten Sie beispielsweise die folgende Tabelle:

CREATE TABLE t1(id integer primary key, value integer, description varchar);

Die REPLICA-IDENTITÄT verwendet den Standardschlüssel id, der die Standardeinstellung ist.

Sie können das folgende INSERT auf dem Abonnenten sicher ausführen:

INSERT INTO t1 VALUES (100, 1024, 'test');

Aber wenn Sie ein INSERT mit identischem Primärschlüsselwert auf dem Herausgeber ausführen, z.B.:

INSERT INTO t1 VALUES (100, 65536, 'test on publisher');

wird Ihnen auf dem Abonnentenknoten eine Fehlermeldung, wie folgt, angezeigt:

ERROR: duplicate key value violates unique constraint "t1_pkey"
DETAIL: Key (id) = (100) already exists.

Die Replikation wird gestoppt und WAL-Segmente werden auf dem Herausgeber gesammelt. Glücklicherweise enthält das Protokoll alle erforderlichen Informationen und Sie müssen die problematische Zeile mit folgendem Befehl auf dem Abonnenten löschen:

DELETE FROM t1 WHERE id=100;

Anschließend wird die Replikation automatisch neu gestartet.

Szenario 2:
Daten auf der Abonnentenseite aktualisieren

Solange die erforderlichen Berechtigungen gewährt werden, können UPDATE-Anweisungen ohne Fehler oder Warnungen auf dem Abonnenten ausgeführt werden. Die Replikation wird nicht angehalten. Der Herausgeber weiß jedoch nichts über die Änderung. Infolgedessen können sich die Werte in derselben Zeile zwischen Herausgeber und Abonnent unterscheiden. Wenn jedoch dieselbe Zeile beim Herausgeber aktualisiert wird, wird die gesamte Zeile beim Abonnenten überschrieben und die Änderung wird gelöscht, selbst wenn die Änderungen an verschiedenen Spalten vorgenommen wurden.

Szenario 3:
Daten auf der Abonnentenseite löschen

Diese Art von Inkonsistenz führt nicht dazu, dass die Replikation gestoppt wird. Wenn Ihr Konfigurationsparameter log_min_messages auf einen niedrigeren Wert als debug1 eingestellt ist, werden Sie ihn wahrscheinlich nicht bemerken. Wenn Sie Debug-Meldungen protokollieren und eine Zeile im Herausgeber aktualisieren/löschen, die auf dem Abonnenten nicht vorhanden ist, sollten Sie folgende Protokolleinträge auf dem Abonnentenknoten erwarten:

DEBUG: logical replication did not find row for update in replication target relation "t1"
DEBUG: logical replication did not find row for delete in replication target relation "t1"

Manchmal ist es erwünscht, einen kleineren Datensatz auf dem Abonnenten zu halten und solche Nachrichten können sicher ignoriert werden. Aber was ist, wenn es eine Inkonsistenz ist, die gelöst werden muss? Leider bietet die native logische Replikation im Gegensatz zu pglogical keine Tools zum erneuten Synchronisieren der Tabelle.
Dafür gibt es allerdings einen weiteren Weg dieses Problem zu umgehen.

Wie synchronisiere ich eine Tabelle in der logischen PostgreSQL-Replikation neu?

Sie haben hier verschiedene Möglichkeiten:

  1. Sperren Sie die Tabelle für Schreibvorgänge auf dem Herausgeber, sichern Sie die Daten und kopieren Sie diesen Speicherauszug auf den Abonnenten. Leeren Sie die Tabelle auf dem Abonnenten, stellen Sie einen Datendump auf dem Abonnenten wieder her und entfernen Sie die Sperre für den Herausgeber.
  2. Schließen Sie die Tabelle von der aktuellen Veröffentlichung aus, leeren Sie die Tabelle bei dem Abonnenten und erstellen Sie ein neues Veröffentlichungs-Abonnement-Paar.

Wenn es Ihnen nichts ausmacht, die Systemkataloge von Hand zu bearbeiten, gibt es noch eine weitere Möglichkeiten:

💡Beachten Sie, dass Sie unbedingt über ein Backup verfügen sollten, wenn sie fortfahren.

Der Status logisch replizierter Tabellen wird in einer Tabelle pg_subscription_rel gespeichert. Die Spalte srsubstate gibt an, ob die Tabelle initialisiert wird, Daten kopiert und synchronisiert werden oder ob die Replikation bereit ist. Wenn Sie den Wert in i ändern, was initial bedeutet, können Sie das Starten der anfänglichen Synchronisation erzwingen. Führen Sie den folgenden Befehl für den Abonnenten aus, um eine Tabelle mit dem Namen t1 erneut zu synchronisieren:

TRUNCATE TABLE t1;
UPDATE pg_subscription_rel SET srsubstate = 'i' WHERE srrelid = (SELECT relid FROM pg_stat_user_tables WHERE schemaname='public' AND relname='t1');

(Wenn sich die Tabelle in einem anderen Schema befindet, ersetzen Sie public durch den entsprechenden Schemanamen.)

Überprüfen Sie nach einer Weile die Tabelle pg_subscription_rel. Der Status sollte sich automatisch zunächst in d, dann s und schließlich in r ändern, was bedeutet, dass die Neusynchronisation abgeschlossen ist. Wenn der Status bei d hängt, überprüfen Sie die Protokolle und pg_stat_replication am Herausgeberknoten. Wenn die Replikation aufgrund eines doppelten Primärschlüsselwerts fehlschlägt, löschen Sie die Daten auf dem Abonnenten, überprüfen Sie ob die Zeilenanzahl tatsächlich Null ist und wiederholen Sie die Aktualisierung von pg_subscription_rel.


→ Hier findest Du den Artikel zum direkten PDF-Download: madafa.de/download/artikel-downloads/


Schreibe einen Kommentar