Aktiv-aktive Konflikte verstehen - Amazon Relational Database Service

Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.

Aktiv-aktive Konflikte verstehen

Wenn Sie pgactive im Active-Active-Modus verwenden, kann das Schreiben in dieselben Tabellen von mehreren Knoten aus zu Datenkonflikten führen. Während einige Clustersysteme verteilte Sperren verwenden, um gleichzeitigen Zugriff zu verhindern, verfolgt pgactive einen optimistischen Ansatz, der sich besser für geografisch verteilte Anwendungen eignet.

Einige Datenbank-Clustersysteme verhindern den gleichzeitigen Datenzugriff, indem sie verteilte Sperren verwenden. Dieser Ansatz funktioniert zwar, wenn sich Server in unmittelbarer Nähe befinden, unterstützt jedoch keine geografisch verteilten Anwendungen, da er für eine gute Leistung eine extrem niedrige Latenz erfordert. Anstatt verteilte Sperren zu verwenden (ein pessimistischer Ansatz), verwendet die Erweiterung pgactive einen optimistischen Ansatz. Das heißt:

  • Hilft Ihnen, Konflikte nach Möglichkeit zu vermeiden.

  • Ermöglicht das Auftreten bestimmter Arten von Konflikten.

  • Ermöglicht die Konfliktlösung, wenn Konflikte auftreten.

Dieser Ansatz bietet Ihnen mehr Flexibilität beim Erstellen verteilter Anwendungen.

Wie Konflikte entstehen

Konflikte zwischen Knoten entstehen durch Abfolgen von Ereignissen, die nicht eintreten könnten, wenn alle beteiligten Transaktionen gleichzeitig auf demselben Knoten stattfänden. Da die Knoten erst nach dem Commit der Transaktion Änderungen austauschen, ist jede Transaktion auf dem Knoten, auf dem sie festgeschrieben wurde, einzeln gültig, wäre aber nicht gültig, wenn sie auf einem anderen Knoten ausgeführt würde, der in der Zwischenzeit andere Aufgaben ausgeführt hat. Da pgactive apply die Transaktion im Wesentlichen auf den anderen Knoten wiedergibt, kann der Wiedergabevorgang fehlschlagen, wenn ein Konflikt zwischen einer angewendeten Transaktion und einer Transaktion besteht, die auf dem empfangenden Knoten festgeschrieben wurde.

Der Grund, warum die meisten Konflikte nicht auftreten können, wenn alle Transaktionen auf einem einzigen Knoten ausgeführt werden, ist, dass PostgreSQL über Kommunikationsmechanismen zwischen Transaktionen verfügt, um dies zu verhindern, darunter:

  • EINDEUTIGE Indizes

  • SEQUENCEs

  • Sperren von Zeilen und Beziehungen

  • SERIALISIERBARE ABHÄNGIGKEITSVERFOLGUNG

All diese Mechanismen dienen der Kommunikation zwischen Transaktionen, um unerwünschte Parallelitätsprobleme zu vermeiden

pgactive erreicht eine geringe Latenz und verarbeitet Netzwerkpartitionen gut, da es keinen verteilten Transaktionsmanager oder Sperrmanager verwendet. Dies bedeutet jedoch, dass Transaktionen auf verschiedenen Knoten völlig isoliert voneinander ausgeführt werden. Während die Isolierung in der Regel die Datenbankkonsistenz verbessert, müssen Sie in diesem Fall die Isolation reduzieren, um Konflikte zu vermeiden.

Arten von Konflikten

Zu den Konflikten, die auftreten können, gehören:

Konflikte mit PRIMARY KEY oder UNIQUE

Zeilenkonflikte treten auf, wenn mehrere Operationen versuchen, denselben Zeilenschlüssel auf eine Weise zu ändern, die auf einem einzelnen Knoten nicht möglich ist. Diese Konflikte stellen die häufigste Art von Datenkonflikten dar.

pgactive löst erkannte Konflikte durch die last-update-wins Behandlung oder Ihren benutzerdefinierten Konflikthandler.

Zu den Zeilenkonflikten gehören:

  • INSERT gegen INSERT

  • INSERT gegen UPDATE

  • AKTUALISIEREN gegen LÖSCHEN

  • EINFÜGEN gegen LÖSCHEN

  • LÖSCHEN gegen LÖSCHEN

  • EINFÜGEN gegen LÖSCHEN

INSERT/INSERT-Konflikte

Dieser häufigste Konflikt tritt auf, wenn INSERTs auf zwei verschiedenen Knoten ein Tupel mit denselben PRIMARY KEY-Werten (oder identischen UNIQUE-Einschränkungswerten, wenn kein PRIMARY KEY vorhanden ist) erstellt wird.

pgactivelink löst INSERT-Konflikte, indem es den Zeitstempel des ursprünglichen Hosts verwendet, um das neueste Tupel beizubehalten. Sie können dieses Standardverhalten mit Ihrem benutzerdefinierten Konflikthandler außer Kraft setzen. Dieser Prozess erfordert zwar keine spezielle Administratoraktion, aber beachten Sie, dass pgactivelink eine der INSERT-Operationen auf allen Knoten verwirft. Es findet keine automatische Datenzusammenführung statt, es sei denn, Ihr benutzerdefinierter Handler implementiert sie.

Der pgactivelink kann nur Konflikte lösen, bei denen es sich um eine einzige Einschränkungsverletzung handelt. Wenn ein INSERT gegen mehrere UNIQUE-Einschränkungen verstößt, müssen Sie zusätzliche Strategien zur Konfliktlösung implementieren.

INSERTsdie gegen mehrere UNIQUE-Einschränkungen verstoßen

Ein INSERT/INSERT-Konflikt kann mehrere UNIQUE-Einschränkungen verletzen, einschließlich des PRIMARY KEY. pgactivelink kann nur Konflikte behandeln, die eine einzige UNIQUE-Einschränkung beinhalten. Wenn Konflikte mehrere UNIQUE-Einschränkungen verletzen, schlägt der Apply-Worker fehl und gibt den folgenden Fehler zurück:

multiple unique constraints violated by remotely INSERTed tuple.

In älteren Versionen führte diese Situation stattdessen zu dem Fehler „Konflikt um unterschiedliche Eindeutigkeit“.

Um diese Konflikte zu lösen, müssen Sie manuelle Maßnahmen ergreifen. LÖSCHEN Sie entweder die widersprüchlichen lokalen Tupel oder AKTUALISIEREN Sie sie, um Konflikte mit dem neuen Remote-Tupel zu beseitigen. Beachten Sie, dass Sie sich möglicherweise mit mehreren in Konflikt stehenden Tupeln befassen müssen. Derzeit bietet pgactivelink keine integrierte Funktionalität zum Ignorieren, Verwerfen oder Zusammenführen von Tupeln, die gegen mehrere eindeutige Einschränkungen verstoßen.

Anmerkung

Weitere Informationen finden Sie unter UPDATEs Diese verstoßen gegen mehrere UNIQUE-Einschränkungen.

UPDATE/UPDATE-Konflikte

Dieser Konflikt tritt auf, wenn zwei Knoten gleichzeitig dasselbe Tupel ändern, ohne seinen PRIMÄRSCHLÜSSEL zu ändern. pgactivelink löst diese Konflikte mithilfe von last-update-wins Logik oder Ihrem benutzerdefinierten Konflikthandler, falls definiert. Ein PRIMÄRSCHLÜSSEL ist für den Tupelabgleich und die Konfliktlösung unerlässlich. Für Tabellen ohne PRIMARY KEY lehnt pgactivelink UPDATE-Operationen mit dem folgenden Fehler ab:

Cannot run UPDATE or DELETE on table (tablename) because it does not have a primary key.

UPDATE-Konflikte beim PRIMARY KEY

pgactive hat Einschränkungen beim Umgang mit PRIMARY KEY-Updates. Sie können zwar eine UPDATE-Operation für einen PRIMÄRSCHLÜSSEL ausführen, aber pgactive kann Konflikte nicht automatisch mithilfe der last-update-wins Logik für diese Operationen lösen. Sie müssen sicherstellen, dass Ihre PRIMARY KEY-Aktualisierungen nicht mit vorhandenen Werten in Konflikt geraten. Wenn bei PRIMARY KEY-Aktualisierungen Konflikte auftreten, werden diese zu divergierenden Konflikten, die Ihr manuelles Eingreifen erfordern. Weitere Informationen zum Umgang mit diesen Situationen finden Sie unter. Divergierende Konflikte

UPDATEsdie gegen mehrere UNIQUE-Einschränkungen verstoßen

pgactivelink kann keine last-update-wins Konfliktlösung anwenden, wenn ein eingehendes UPDATE gegen mehrere UNIQUE-Einschränkungen oder PRIMARY KEY-Werte verstößt. Dieses Verhalten ähnelt INSERT-Vorgängen mit mehreren Einschränkungsverletzungen. Diese Situationen führen zu unterschiedlichen Konflikten, die Ihr manuelles Eingreifen erfordern. Weitere Informationen finden Sie unter Divergierende Konflikte.

Konflikte beim Aktualisieren/Löschen

Diese Konflikte treten auf, wenn UPDATEs ein Knoten eine Zeile und ein anderer Knoten gleichzeitig DELETEs vorhanden ist. In diesem Fall tritt bei der Wiedergabe ein UPDATE/DELETE-Konflikt auf. Die Lösung besteht darin, alle AKTUALISIERUNGEN, die nach einem DELETE-Befehl eintreffen, zu verwerfen, sofern Ihr benutzerdefinierter Konflikthandler nichts anderes festlegt.

pgactivelink benötigt einen PRIMÄRSCHLÜSSEL, um Tupel abzugleichen und Konflikte zu lösen. Für Tabellen ohne PRIMARY KEY lehnt es DELETE-Operationen mit dem folgenden Fehler ab:

Cannot run UPDATE or DELETE on table (tablename) because it does not have a primary key.

Anmerkung

pgactivelink kann nicht zwischen Konflikten unterscheiden. UPDATE/DELETE and INSERT/UPDATE In beiden Fällen wirkt sich ein UPDATE auf eine Zeile aus, die nicht existiert. Aufgrund der asynchronen Replikation und der fehlenden Reihenfolge der Wiedergabe zwischen den Knoten kann pgactivelink nicht feststellen, ob das UPDATE für eine neue Zeile (INSERT noch nicht empfangen) oder für eine gelöschte Zeile gilt. In beiden Szenarien verwirft pgactivink das UPDATE.

INSERT/UPDATE-Konflikte

Dieser Konflikt kann in Umgebungen mit mehreren Knoten auftreten. Er tritt auf, wenn INSERTs ein Knoten eine Zeile, ein zweiter Knoten UPDATEs sie und ein dritter Knoten das UPDATE vor dem ursprünglichen INSERT empfängt. Standardmäßig löst pgactivelink diese Konflikte, indem es das UPDATE verwirft, sofern Ihr benutzerdefinierter Konflikt-Trigger nichts anderes angibt. Beachten Sie, dass diese Lösungsmethode zu Dateninkonsistenzen zwischen den Knoten führen kann. Weitere Informationen zu ähnlichen Szenarien und deren Handhabung finden Sie unter. Konflikte beim Aktualisieren/Löschen

Konflikte löschen/löschen

Dieser Konflikt tritt auf, wenn zwei verschiedene Knoten gleichzeitig dasselbe Tupel löschen. pgactivelink betrachtet diese Konflikte als harmlos, da beide DELETE-Operationen dasselbe Endergebnis haben. In diesem Szenario ignoriert pgactivink sicher eine der DELETE-Operationen, ohne die Datenkonsistenz zu beeinträchtigen.

Konflikte mit Foreign Key Constraint

FOREIGN KEY-Einschränkungen können zu Konflikten führen, wenn Remotetransaktionen auf vorhandene lokale Daten angewendet werden. Diese Konflikte treten typischerweise auf, wenn Transaktionen in einer anderen Reihenfolge als in ihrer logischen Reihenfolge auf den Ausgangsknoten angewendet werden.

Standardmäßig wendet pgactive Änderungen mit session_replication_role as an, wodurch Fremdschlüsselprüfungen während der Replikation replica umgangen werden. In Active-Active-Konfigurationen kann dies zu Verletzungen von Fremdschlüsseln führen. Die meisten Verstöße sind vorübergehend und werden behoben, sobald die Replikation abgeschlossen ist. Allerdings kann es zu fehlerhaften Fremdschlüsseln kommen, weil pgactive das knotenübergreifende Sperren von Zeilen nicht unterstützt.

Dieses Verhalten ist partitionstoleranten asynchronen aktiv-aktiven Systemen inhärent. Beispielsweise könnte Knoten A eine neue untergeordnete Zeile einfügen, während Knoten B gleichzeitig seine übergeordnete Zeile löscht. Das System kann diese Art der gleichzeitigen Änderung knotenübergreifend nicht verhindern.

Um Fremdschlüsselkonflikte zu minimieren, empfehlen wir Folgendes:

  • Beschränken Sie Fremdschlüsselbeziehungen auf eng verwandte Entitäten.

  • Ändern Sie verwandte Entitäten, wenn möglich, von einem einzigen Knoten aus.

  • Wählen Sie Entitäten aus, die selten geändert werden müssen.

  • Implementieren Sie die Parallelitätssteuerung auf Anwendungsebene für Änderungen.

Konflikte zwischen Ausschlussbeschränkungen

pgactive link unterstützt keine Ausschlussbeschränkungen und schränkt deren Erstellung ein.

Anmerkung

Wenn Sie eine bestehende eigenständige Datenbank in eine pgactivink-Datenbank konvertieren, löschen Sie manuell alle Ausschlussbeschränkungen.

In einem verteilten asynchronen System kann nicht garantiert werden, dass kein Satz von Zeilen gegen die Einschränkung verstößt. Dies liegt daran, dass alle Transaktionen auf verschiedenen Knoten vollständig isoliert sind. Ausschlussbeschränkungen können zu Deadlocks bei der Wiedergabe führen, sodass die Wiedergabe aufgrund von Verstößen gegen Ausschlussbeschränkungen nicht von einem Knoten zum anderen fortgesetzt werden kann.

Wenn Sie pgactive Link zwingen, eine Ausschlussbeschränkung zu erstellen, oder wenn Sie bei der Konvertierung einer eigenständigen Datenbank in pgactive Link bestehende Einschränkungen nicht löschen, ist es wahrscheinlich, dass die Replikation unterbrochen wird. Um den Replikationsfortschritt wiederherzustellen, entfernen oder ändern Sie die lokalen Tupel, die mit einem eingehenden Remote-Tupel in Konflikt stehen, sodass die Remotetransaktion angewendet werden kann.

Globale Datenkonflikte

Bei der Verwendung von pgactivelink können Konflikte auftreten, wenn Knoten unterschiedliche globale systemweite PostgreSQL-Daten haben, z. B. Rollen. Diese Konflikte können dazu führen, dass Operationen — in erster Linie DDL — auf einem Knoten erfolgreich ausgeführt und festgeschrieben werden, aber nicht auf andere Knoten angewendet werden.

Wenn ein Benutzer auf einem Knoten existiert, auf einem anderen aber nicht, können Replikationsprobleme auftreten:

  • Node1 hat einen Benutzer namensfred, aber dieser Benutzer existiert nicht auf Node2

  • Wenn eine Tabelle auf Node1 fred erstellt wird, wird die Tabelle mit dem Eigentümer repliziert fred

  • Wenn dieser DDL-Befehl auf Node2 angewendet wird, schlägt er fehl, weil der Benutzer nicht existiert fred

  • Dieser Fehler generiert einen FEHLER in den PostgreSQL-Protokollen auf Node2 und erhöht den Zähler. pgactive.pgactive_stats.nr_rollbacks

Lösung: Erstellen Sie den Benutzer auf Node2. fred Der Benutzer benötigt keine identischen Berechtigungen, sondern muss auf beiden Knoten vorhanden sein.

Wenn eine Tabelle auf einem Knoten existiert, auf einem anderen aber nicht, schlagen Datenänderungsvorgänge fehl:

  • Node1 hat eine Tabelle mit dem Namenfoo, die auf Node2 nicht existiert

  • Alle DML-Operationen in der foo Tabelle auf Node1 schlagen fehl, wenn sie auf Node2 repliziert werden

Lösung: Erstellen Sie die Tabelle foo auf Node2 mit derselben Struktur.

Anmerkung

pgactivelink repliziert derzeit keine CREATE USER-Befehle oder DDL-Operationen. Die DDL-Replikation ist für eine future Version geplant.

Sperrkonflikte und Deadlock-Abbrüche

Da pgactive-Apply-Prozesse wie normale Benutzersitzungen funktionieren, folgen sie den Standardregeln für das Sperren von Zeilen und Tabellen. Dies kann dazu führen, dass pgactivink-Apply-Prozesse auf Sperren warten, die von Benutzertransaktionen oder anderen Apply-Prozessen gehalten werden.

Die folgenden Arten von Sperren können sich auf Apply-Prozesse auswirken:

  • Explizites Sperren auf Tabellenebene (LOCK TABLE...) durch Benutzersitzungen

  • Explizites Sperren auf Zeilenebene (SELECT... FOR UPDATE/FOR SHARE) nach Benutzersitzungen

  • Sperren mit Fremdschlüsseln

  • Implizites Sperren aufgrund von Zeilen UPDATEs INSERTs, oder DELETEs, entweder aufgrund lokaler Aktivitäten oder aufgrund von Angriffen von anderen Servern

Deadlocks können auftreten zwischen:

  • Ein pgactivelink-Apply-Prozess und eine Benutzertransaktion

  • Zwei Apply-Prozesse

Wenn Deadlocks auftreten, beendet der Deadlock-Detektor von PostgreSQL eine der problematischen Transaktionen. Wenn der Prozess des Apply-Workers pgactivelink beendet wird, versucht er es automatisch erneut, was in der Regel erfolgreich ist.

Anmerkung
  • Diese Probleme sind vorübergehend und erfordern im Allgemeinen kein Eingreifen des Administrators. Wenn ein Apply-Prozess durch eine Sperre einer Benutzersitzung im Leerlauf für einen längeren Zeitraum blockiert wird, können Sie die Benutzersitzung beenden, um die Replikation fortzusetzen. Diese Situation ähnelt der Situation, wenn ein Benutzer eine lange Sperre hält, die sich auf eine andere Benutzersitzung auswirkt.

  • Um Verzögerungen bei der Wiedergabe im Zusammenhang mit Sperren zu identifizieren, aktivieren Sie die log_lock_waits Funktion in PostgreSQL.

Divergierende Konflikte

Divergierende Konflikte treten auf, wenn Daten, die knotenübergreifend identisch sein sollten, unerwartet voneinander abweichen. Diese Konflikte sollten zwar nicht auftreten, aber mit der aktuellen Implementierung können nicht alle zuverlässig verhindert werden.

Anmerkung

Das Ändern des PRIMÄRSCHLÜSSELS einer Zeile kann zu unterschiedlichen Konflikten führen, wenn ein anderer Knoten den Schlüssel derselben Zeile ändert, bevor alle Knoten die Änderung verarbeiten. Vermeiden Sie es, Primärschlüssel zu ändern, oder beschränken Sie Änderungen auf einen bestimmten Knoten. Weitere Informationen finden Sie unter UPDATE-Konflikte beim PRIMARY KEY .

Divergierende Konflikte, die Zeilendaten betreffen, erfordern in der Regel ein Eingreifen des Administrators. Um diese Konflikte zu lösen, müssen Sie die Daten auf einem Knoten manuell so anpassen, dass sie einem anderen entsprechen, und gleichzeitig die Replikation mithilfe von vorübergehend deaktivieren. pgactive.pgactive_do_not_replicate Diese Konflikte sollten nicht auftreten, wenn Sie pgactive wie dokumentiert verwenden und Einstellungen oder Funktionen vermeiden, die als unsicher markiert sind.

Als Administrator müssen Sie diese Konflikte manuell lösen. Je nach Konflikttyp müssen Sie erweiterte Optionen wie verwendenpgactive.pgactive_do_not_replicate. Verwenden Sie diese Optionen mit Vorsicht, da eine unsachgemäße Verwendung die Situation verschlimmern kann. Aufgrund der Vielzahl möglicher Konflikte können wir keine allgemeingültigen Lösungsansätze bereitstellen.

Divergierende Konflikte treten auf, wenn sich Daten, die auf verschiedenen Knoten identisch sein sollten, unerwartet unterscheiden. Diese Konflikte sollten zwar nicht auftreten, aber nicht alle dieser Konflikte können in der aktuellen Implementierung zuverlässig verhindert werden.

Konflikte vermeiden oder tolerieren

In den meisten Fällen können Sie ein geeignetes Anwendungsdesign verwenden, um Konflikte zu vermeiden oder Ihre Anwendung konflikttolerant zu machen.

Konflikte treten nur auf, wenn gleichzeitige Operationen auf mehreren Knoten ausgeführt werden. Um Konflikte zu vermeiden:

  • Schreiben Sie nur auf einen Knoten

  • Schreiben Sie in unabhängige Datenbankuntergruppen auf jedem Knoten (weisen Sie beispielsweise jedem Knoten ein eigenes Schema zu)

Verwenden Sie bei INSERT- und INSERT-Konflikten globale Sequenzen, um Konflikte vollständig zu vermeiden.

Wenn Konflikte für Ihren Anwendungsfall nicht akzeptabel sind, sollten Sie die Implementierung verteilter Sperren auf Anwendungsebene in Betracht ziehen. Oft ist es am besten, Ihre Anwendung so zu gestalten, dass sie mit den Konfliktlösungsmechanismen von pgactive funktioniert, anstatt zu versuchen, alle Konflikte zu verhindern. Weitere Informationen finden Sie unter Arten von Konflikten.

Protokollierung von Konflikten

pgactivelink protokolliert Konfliktereignisse in der pgactive.pgactive_conflict_history Tabelle, um Ihnen bei der Diagnose und Behandlung von Active-Active-Konflikten zu helfen. Die Konfliktprotokollierung in dieser Tabelle erfolgt nur, wenn Sie den Wert auf true setzen. pgactive.log_conflicts_to_table Die Erweiterung pgactive protokolliert auch Konflikte in der PostgreSQL-Protokolldatei, wenn log_min_messages auf oder gesetzt ist, unabhängig von der Einstellung. LOG lower pgactive.log_conflicts_to_table

Verwenden Sie die Tabelle mit dem Konfliktverlauf, um:

  • Messen Sie, wie häufig Ihre Anwendung Konflikte verursacht

  • Identifizieren Sie, wo Konflikte auftreten

  • Verbessern Sie Ihre Anwendung, um die Konfliktrate zu reduzieren

  • Erkennen Sie Fälle, in denen Konfliktlösungen nicht zu den gewünschten Ergebnissen führen

  • Ermitteln Sie, wo Sie benutzerdefinierte Konfliktauslöser oder Änderungen am Anwendungsdesign benötigen

Bei Zeilenkonflikten können Sie optional Zeilenwerte protokollieren. Dies wird durch die pgactive.log_conflicts_to_table Einstellung gesteuert. Beachten Sie:

  • Dies ist eine globale datenbankweite Option

  • Es gibt keine Kontrolle über die Protokollierung von Zeilenwerten pro Tabelle

  • Für Feldnummern, Array-Elemente oder Feldlängen gelten keine Beschränkungen

  • Die Aktivierung dieser Funktion ist möglicherweise nicht ratsam, wenn Sie mit Zeilen mit mehreren Megabyte arbeiten, die Konflikte auslösen könnten

Da die Konfliktverlaufstabelle Daten aus jeder Tabelle in der Datenbank enthält (jede mit potenziell unterschiedlichen Schemas), werden protokollierte Zeilenwerte als JSON-Felder gespeichert. Die JSON-Datei wird mithilfe von SQL erstelltrow_to_json, ähnlich wie wenn sie direkt aus SQL aufgerufen wird. PostgreSQL bietet keine json_to_row Funktion, daher benötigen Sie tabellenspezifischen Code (in usw.)PL/pgSQL, PL/Python, PL/Perl, um ein zusammengesetztes Tupel aus dem protokollierten JSON zu rekonstruieren.

Anmerkung

Die Support von benutzerdefinierten Konflikten ist als future Erweiterungsfunktion geplant.