Fantastische Beratungsschlösser und wo sie leben

PostgreSQL verfügt über einen sehr praktischen Mechanismus für Beratungssperren . Sie sind auch Beratungssperren . Wir bei Tensor verwenden sie an vielen Stellen im System, aber nur wenige Menschen verstehen im Detail, wie genau sie funktionieren und welche Probleme bei Misshandlung auftreten können .



Lesen Sie mehr über Schlösser

Vorteile von Empfehlungsschlössern


Der grundlegende Unterschied zwischen diesem Mechanismus und „normalen“ Sperren auf Tabellen-, Seiten- und Datensatzebene besteht darin, dass es mehrere Hauptmerkmale gibt.

Benutzerdefinierte ID-Sperre


"Normale" Sperren in PG sind immer an ein bestimmtes Datenbankobjekt (Tabelle, Datensatz, Datenseite) und den Prozess gebunden, der die Verbindung bedient. Beratungssperren sind ebenfalls ein Prozess, aber anstelle eines realen Objekts kann ein abstrakter Bezeichner als (bigint) oder als (integer, integer) festgelegt werden .

Übrigens bedeutet das Anhängen jeder Sperre an einen Prozess, dass Sie durch Benennen pg_terminate_backend(pid)oder korrekte Vervollständigung der Verbindung von der Clientseite aus alle von ihr auferlegten Sperren entfernen können.

CAS Auf Sperrerfassung prüfen


CAS ist ein Compare-and-Set , dh die Überprüfung der Erfassungsfähigkeit und die Erfassung des Schlosses selbst erfolgt als eine atomare Operation, und offensichtlich kann sich niemand zwischen ihnen verkeilen.

Das heißt, wenn Sie zuerst eine Überprüfungsanforderung an pg_locks stellen , das Ergebnis anzeigen und dann entscheiden, ob gesperrt werden soll oder nicht, kann niemand garantieren, dass zwischen diesen Vorgängen niemand das gewünschte Objekt übernehmen kann. Wenn Sie jedoch pg_try_advisory_lock verwenden , erhalten Sie diese Sperre entweder sofort oder die Funktion kehrt einfach zurück FALSE.

No-Capture ohne Ausnahmen und Erwartungen


Im Modell gibt es „normale“ Sperren. „Wenn Sie bereits nach einer Sperre gefragt haben, warten Sie. Wenn Sie nicht wollen warten ( NOWAIT, statement_timeout, lock_timeout) - hier ist eine Ausnahme " . Dieser Ansatz stört die Transaktion erheblich, da Sie dann entweder einen Block BEGIN-EXCEPTION-ENDfür die Verarbeitung implementieren oder ROLLBACKdie Transaktion zurücksetzen ( ) müssen.

Die einzige Möglichkeit, dieses Verhalten zu vermeiden, besteht darin, das SELECT ... SKIP LOCKEDmit Version 9.5 gelieferte Design zu verwenden . Leider sind bei dieser Methode die Optionen "hatten überhaupt nichts zu blockieren" und "war, aber bereits blockiert" nicht mehr zu unterscheiden.

Empfohlene Sperren, die durch Try- Funktionen verursacht werden , kehren einfach zurück TRUE/FALSE.
Nicht verwirren pg_advisory_lockund - die erste Funktion wartet, bis sie eine Sperre erhält, und die zweite Funktion kehrt einfach sofort zurück, wenn es "jetzt" nicht möglich ist, sie zu erfassen.pg_try_advisory_lockFALSE

Sperren innerhalb und nach der Transaktion


Wie oben erwähnt, sind Objektsperren an den Prozess „angehängt“ und existieren nur als Teil der aktuellen Transaktion darin. Auch nur aufzuzwingen - wird nicht gelingen:

LOCK TABLE tbl;
-- ERROR:  LOCK TABLE can only be used in transaction blocks

Dementsprechend werden am Ende der Transaktion alle ihr auferlegten Sperren entfernt. Im Gegensatz dazu wurden Beratungsschlösser ursprünglich mit der Fähigkeit entwickelt, Schlösser zu halten und außerhalb des Umfangs einer Transaktion :

SELECT pg_advisory_lock(1);
SELECT * FROM pg_locks WHERE pid = pg_backend_pid() AND locktype = 'advisory';

-[ RECORD 1 ]------+--------------
locktype           | advisory
database           | 263911484
relation           |
page               |
tuple              |
virtualxid         |
transactionid      |
classid            | 0 <--  int4 #1    int8
objid              | 1 <--  int4 #2    int8
objsubid           | 1
virtualtransaction | 416/475768
pid                | 29264
mode               | ExclusiveLock
granted            | t
fastpath           | f

Aber bereits ab Version 9.1 sind xact- Versionen von Beratungsfunktionen erschienen , mit denen Sie das Verhalten von „normalen“ Sperren implementieren können, die automatisch freigegeben werden, wenn die Transaktion, die sie auferlegt hat, abgeschlossen ist.

Anwendungsbeispiele in VLSI


Wie bei jeder anderen Sperre dient die Beratung dazu, die Einzigartigkeit der Verarbeitung einer Ressource sicherzustellen. In unserem Land sind solche Ressourcen normalerweise entweder die gesamte Tabelle oder ein bestimmter Datensatz der Tabelle, der aus irgendeinem Grund nicht "gesperrt" werden möchte.

Arbeiter-Monoverarbeitung


Wenn die Notwendigkeit, einige Daten in der Datenbank zu verarbeiten, durch ein externes Ereignis ausgelöst wird, die Verarbeitung mehrerer Prozesse jedoch redundant ist oder zu einer Race-Bedingung führen kann , ist es sinnvoll, jeweils nur einen Prozess für diese Daten zu verwenden .

Zu diesem Zweck versuchen wir, die Tabellenkennung als ersten Parameter und die spezifische Anwendungsverarbeitungs-ID als zweiten Parameter zu verwenden:

SELECT pg_try_advisory_lock(
  'processed_table'::regclass::oid
, -1 --   worker'
);

Wenn wir zurückkehren FALSE, hält bereits jemand anderes ein solches Schloss in der Hand, und speziell dieser Prozess muss nichts tun, aber es ist am besten, einfach leise zu enden. So funktioniert beispielsweise der Prozess der dynamischen Berechnung der Warenkosten in einem Lager für jedes einzelne Kundenschema isoliert.

Gleichzeitige Warteschlangenverarbeitung


Jetzt ist die Aufgabe „das Gegenteil“ - wir möchten, dass die Aufgaben in einer Warteschlangentabelle so schnell wie möglich verarbeitet werden, multithreaded, fehlertolerant und sogar aus unterschiedlichen Geschäftslogiken (wir haben nicht die Leistung einer) - zum Beispiel wie unser Operator über die Übermittlung der elektronischen Berichterstattung an Regierungsbehörden oder den OFD-Dienst .

Da es sich bei den "verarbeitenden" BLs um unterschiedliche Server handelt, kann kein Mutex mehr aufgehängt werden. Es ist nicht sicher, einen speziellen Prozesskoordinator für die Verteilung von Aufgaben auszuwählen, "stirbt" er - und alles wird steigen. Und so stellt sich heraus, dass es am effizientesten ist, Aufgaben direkt auf Datenbankebene zu verteilen, und es gibt eine solche Methode - in der Antike wurde das Modell von Dmitry Koterov ehrlich ausspioniert und dann kreativ modifiziert.

In diesem Fall wird die Tabellen-ID und die PK eines bestimmten Datensatzes gesperrt:

SELECT
  *
FROM
  queue_table
WHERE
  pg_try_advisory_lock('queue_table'::regclass::oid, pk_id)
ORDER BY
  pk_id
LIMIT 1;

Das heißt, der Prozess erhält von der Tabelle den ersten Datensatz, der von seinen konkurrierenden Brüdern noch nicht blockiert wurde.

Wenn PK jedoch nicht aus (Ganzzahl) , sondern aus (Ganzzahl, Ganzzahl) besteht (wie beispielsweise bei derselben Kostenberechnung), können Sie diesem Paar direkt eine Sperre auferlegen - es ist unwahrscheinlich, dass ein Schnittpunkt mit dem "Konkurrenten" auftritt.

Wichtig! Vergessen Sie nicht, Ihre Warteschlangentabelle regelmäßig ordnungsgemäß zu pflegen !

Exklusive Dokumentenverarbeitung


Es wird überall in Dokumentenverwaltungslösungen verwendet . In einem verteilten Websystem kann zwar ein und dasselbe Dokument zur Anzeige durch verschiedene Benutzer gleichzeitig geöffnet werden, es kann jedoch immer nur von nur einem Dokument verarbeitet werden (Status ändern usw.).

Traditionelle Themen


Wo ohne sie! Fast alles läuft auf eine Sache hinaus : Sie haben nicht freigeschaltet, was sie gesperrt haben .

Mehrfachüberlagerung eines Hinweisschlosses


RTFM , wie sie sagen:
Wenn mehrere Blockierungsanforderungen gleichzeitig empfangen werden, häufen sie sich. Wenn eine Ressource also dreimal blockiert wurde, muss sie dreimal entsperrt werden , um in anderen Sitzungen verfügbar zu sein.

Setzen Sie zu viele Schlösser gleichzeitig




Tausende von ihnen! Lesen Sie das Handbuch noch einmal :
Sowohl empfohlene als auch reguläre Sperren werden im gemeinsam genutzten Speicherbereich gespeichert, dessen Größe durch die Konfigurationsparameter max_locks_per_transactionund bestimmt wird max_connections. Es ist wichtig, dass dieser Speicher ausreichend ist, da der Server sonst keine Sperre ausstellen kann . Daher ist die Anzahl der empfohlenen Sperren, die ein Server ausgeben kann, je nach Serverkonfiguration normalerweise auf Zehntausende oder Hunderttausende begrenzt.

Wenn eine Situation auftritt, in der Sie mehrere tausend Beratungssperren festlegen möchten (auch wenn Sie diese später korrekt entfernen), sollten Sie im Allgemeinen genau überlegen, wo Sie ausgeführt werden, wenn der Server hochfährt.

Lecks beim Filtern von Datensätzen


Hier nehmen wir die vorherige Anfrage und fügen eine harmlose Bedingung wie Paritätsprüfungs-ID - hinzu AND pk_id % 2 = 0. Beide Bedingungen für jeden Eintrag werden überprüft ! Als Ergebnis wurde es pg_try_advisory_lockabgeschlossen, die Sperre wurde überlagert und dann wurde der Datensatz nach Parität gefiltert .



Oder eine Option aus dem Handbuch:
SELECT pg_advisory_lock(id) FROM foo WHERE id = 12345; -- ok
SELECT pg_advisory_lock(id) FROM foo WHERE id > 12345 LIMIT 100; -- !

Das ist alles - die Blockierung bleibt bestehen , aber wir sind uns dessen nicht bewusst. Es wird im schlimmsten Fall mit den richtigen Anfragen behandelt - pg_advisory_unlock_all.

Oh, verwirrt!


Klassiker des Genres ...

Verwirren Sie und fragen Sie sich, warum es lange funktioniert. Aber weil die Nicht-Try-Version wartet . Verwirren Sie und und fragen Sie sich, wohin die Sperre ging - und sie "endete" mit der Transaktion. Und die Transaktion bestand aus einer Anfrage, denn nirgends wurde sie "explizit" deklariert, ja.pg_try_advisory_lockpg_advisory_lock

pg_try_advisory_lockpg_try_advisory_xact_lock

Arbeite durch pgbouncer


Dies ist für viele eine separate Schmerzquelle, wenn die Arbeit mit der Datenbank aus Gründen der Leistung im Transaktionsmodus über pgbouncer erfolgt .

Dies bedeutet, dass zwei Ihrer benachbarten Transaktionen, die auf derselben Verbindung zur Datenbank ausgeführt werden (die tatsächlich den pgbouncer durchläuft), in verschiedenen "physischen" Verbindungen auf der Basisseite ausgeführt werden können . Und sie haben ihre eigenen Schlösser ... Jedes hat



ein paar Möglichkeiten:

  • oder arbeiten Sie über eine direkte Verbindung zur Datenbank
  • oder erfinden Sie einen Algorithmus, sodass sich alle Beratungssperren nur innerhalb der Transaktion befinden (xact)

Das ist alles für jetzt.

All Articles