Technologieaustausch

Wie gehe ich mit der Konfliktlösung für gleichzeitige Datenaktualisierungen in PostgreSQL um?

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

schöne Trennlinie

PostgreSQL


In einer Umgebung mit gleichzeitigem Datenbankbetrieb können mehrere Transaktionen, die gleichzeitig versuchen, dieselben Daten zu aktualisieren, zu Konflikten führen. PostgreSQL bietet eine Reihe von Mechanismen zur Behandlung dieser Konflikte bei gleichzeitigen Aktualisierungen, um die Datenkonsistenz und -integrität sicherzustellen.

schöne Trennlinie

1. Konfliktszenarien bei gleichzeitigen Updates

Konflikte bei der gleichzeitigen Aktualisierung können auftreten, wenn zwei oder mehr Transaktionen gleichzeitig versuchen, dieselbe Datenzeile zu ändern. Zu den häufigsten Szenarien gehören:

  1. Ändern Sie gleichzeitig verschiedene Spalten derselben Zeile
  2. Aktualisieren Sie verschiedene Werte derselben Spalte gleichzeitig

schöne Trennlinie

2. Parallelitätskontrollmechanismus in PostgreSQL

PostgreSQL verwendet hauptsächlich MVCC (Multiversion Concurrency Control), um gleichzeitige Transaktionen abzuwickeln. MVCC ermöglicht es einer Transaktion, eine Datenversion zu lesen, die ihre Isolationsstufenanforderungen erfüllt, ohne die Lesevorgänge anderer Transaktionen zu blockieren, ohne sie zu sperren. Bei Schreibvorgängen kann es jedoch dennoch zu Konflikten kommen.

(1) Blockiermechanismus

PostgreSQL verwendet mehrere Arten von Sperren, um den gleichzeitigen Zugriff auf Daten zu steuern. Zu den gängigen Schlosstypen gehören:

  1. Gemeinsame Sperre: Ermöglicht anderen Transaktionen den Erwerb gemeinsamer Sperren, verhindert jedoch den Erwerb exklusiver Sperren. Wird häufig für Lesevorgänge verwendet.
  2. Exklusive Sperre: Verhindert, dass andere Transaktionen irgendeine Art von Sperre erhalten, die häufig für Schreibvorgänge verwendet wird.

Die Sperrgranularität kann auf Zeilenebene (Row-Level), Seitenebene (Page-Level) und Tabellenebene (Table-Level) liegen.

(2) Transaktionsisolationsstufe

PostgreSQL unterstützt vier Transaktionsisolationsstufen:

  1. Lesen Sie „Uncommitted“.: Dies ist die niedrigste Isolationsstufe. Eine Transaktion kann nicht festgeschriebene Datenänderungen anderer Transaktionen lesen, was zu Problemen wie schmutzigen Lesevorgängen, nicht wiederholbaren Lesevorgängen und Phantom-Lesevorgängen führen kann.
  2. Lesen Sie Committed: Transaktionen können übermittelte Daten nur lesen, wodurch fehlerhafte Lesevorgänge vermieden werden. Es können jedoch weiterhin nicht wiederholbare Lesevorgänge und Phantom-Lesevorgänge auftreten.
  3. Wiederholbares Lesen: Das mehrmalige Lesen derselben Daten innerhalb einer Transaktion führt zum gleichen Ergebnis, wodurch nicht wiederholbare Lesevorgänge vermieden werden, es können jedoch Phantomlesevorgänge auftreten.
  4. Serialisierbar: Die höchste Isolationsstufe, die die serielle Ausführung von Transaktionen durch strikte Parallelitätskontrolle gewährleistet und schmutzige Lesevorgänge, nicht wiederholbare Lesevorgänge und Phantom-Lesevorgänge vermeidet.

schöne Trennlinie

3. Lösung für Konflikte bei gleichzeitigen Updates

(1) Wiederholungsmechanismus

Ein einfacher Ansatz besteht darin, die Transaktion erneut zu versuchen, wenn ein Konflikt auftritt. Beispiele sind wie folgt:

DO
$$
DECLARE
    conflict_detected BOOLEAN := FALSE;
BEGIN
    LOOP
        -- 尝试执行更新操作
        UPDATE products SET price = 100 WHERE id = 1;

        -- 检查是否有冲突(例如,通过检查受影响的行数)
        IF NOT FOUND THEN
            conflict_detected := TRUE;
        ELSE
            EXIT;
        END IF;

        -- 若有冲突,等待一段时间并重试
        IF conflict_detected THEN
            PERFORM pg_sleep(1);
        END IF;
    END LOOP;
END;
$$;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

Wenn sich der Aktualisierungsvorgang im obigen Beispiel auf keine Zeilen auswirkt (was darauf hindeutet, dass möglicherweise ein Konflikt vorliegt), wird ein Flag gesetzt, eine Zeit lang gewartet und es dann erneut versucht.

(2) Verwenden Sie eine optimistische Parallelitätskontrolle

Die optimistische Parallelitätskontrolle geht davon aus, dass Parallelitätskonflikte selten auftreten. Bei dieser Methode wird die Transaktion beim Aktualisieren der Daten nicht gesperrt, sondern beim Festschreiben geprüft, ob die Daten durch andere Transaktionen geändert wurden. Wenn es keine Konflikte gibt, wird die Transaktion erfolgreich festgeschrieben. Wenn es Konflikte gibt, wird die Transaktion zurückgesetzt und bei Bedarf erneut versucht.

-- 获取数据的初始版本
SELECT price AS original_price FROM products WHERE id = 1;

-- 进行业务处理和修改
UPDATE products SET price = 100 WHERE id = 1 AND price = original_price;
  • 1
  • 2
  • 3
  • 4
  • 5

Im obigen Beispiel ist der Aktualisierungsvorgang nur dann erfolgreich, wenn die Daten nicht durch andere Transaktionen geändert wurden.

(3) Verwenden Sie eine pessimistische Parallelitätskontrolle

Die pessimistische Parallelitätskontrolle geht davon aus, dass Parallelitätskonflikte wahrscheinlich auftreten, und erwirbt während der Transaktionsausführung die erforderlichen Sperren, um andere potenziell widersprüchliche Transaktionen zu blockieren.

BEGIN;

-- 获取排他锁
LOCK TABLE products IN SHARE ROW EXCLUSIVE MODE;

-- 进行数据更新
UPDATE products SET price = 100 WHERE id = 1;

COMMIT;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

(4) Feld „Anwendungsversion“.

Fügen Sie der Tabelle ein Versionsfeld hinzu, um Änderungen an den Daten zu verfolgen.

CREATE TABLE products (
    id SERIAL PRIMARY KEY,
    price DECIMAL(10, 2),
    version INT DEFAULT 0
);
  • 1
  • 2
  • 3
  • 4
  • 5

Erhöhen Sie beim Aktualisieren von Daten auch das Versionsfeld:

UPDATE products SET price = 100, version = version + 1 WHERE id = 1 AND version = <expected_version>;
  • 1

Wenn die Anzahl der von der Aktualisierung betroffenen Zeilen 0 beträgt, liegt ein Konflikt vor, da die erwartete Version nicht mit der tatsächlichen Version übereinstimmt.

(5) Konfliktlösung basierend auf Zeitstempel

Fügen Sie jeder Datenzeile ein Zeitstempelfeld hinzu, um den Zeitpunkt der letzten Änderung der Daten aufzuzeichnen.

CREATE TABLE products (
    id SERIAL PRIMARY KEY,
    price DECIMAL(10, 2),
    last_modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
  • 1
  • 2
  • 3
  • 4
  • 5

Aktualisieren Sie beim Aktualisieren nur Daten mit einem Zeitstempel, der älter ist als der von der aktuellen Transaktion gelesene Zeitstempel:

UPDATE products SET price = 100 WHERE id = 1 AND last_modified <= <read_timestamp>;
  • 1

schöne Trennlinie

4. Überlegungen zur praktischen Anwendung

(1) Auswirkungen auf die Leistung

  1. Verschiedene Konfliktlösungsmethoden haben unterschiedliche Auswirkungen auf die Datenbankleistung. Die Verwendung von Blockierungen kann beispielsweise dazu führen, dass andere Transaktionen warten, die Blockierungszeit des Systems verlängern und somit die Parallelität beeinträchtigen. Die optimistische Parallelitätskontrolle ist besser, wenn Konflikte selten auftreten. Wenn Konflikte jedoch häufig auftreten, kann dies zu einer großen Anzahl von Transaktionswiederholungen führen, wodurch sich die Gesamtausführungszeit erhöht.
  2. Das Anwenden von Versionsfeldern oder zeitstempelbasierten Methoden erfordert möglicherweise zusätzlichen Speicherplatz zum Verwalten von Versions- oder Zeitstempelinformationen sowie zusätzliche Beurteilung und Verarbeitung bei der Aktualisierung.

(2) Anpassungsfähigkeit der Geschäftslogik

  1. Bestimmte Geschäftsszenarien eignen sich möglicherweise besser für eine bestimmte Konfliktlösungsmethode. Wenn das Unternehmen beispielsweise sehr hohe Anforderungen an die Datenkonsistenz stellt und keine Inkonsistenzen tolerieren kann, ist die pessimistische Parallelitätskontrolle oder die Serialisierungsisolationsstufe möglicherweise die bessere Wahl.
  2. Eine optimistische Parallelitätskontrolle eignet sich möglicherweise besser für Szenarien, in denen Konflikte weniger häufig auftreten und die Anforderungen an die Reaktionszeit höher sind.

(3) Datenverteilung und Zugriffsmuster

  1. Wenn der Zugriff auf Daten stark gleichzeitig erfolgt und mehrere Transaktionen häufig gleichzeitig auf dieselben Datenzeilen zugreifen, müssen Konfliktlösungsmethoden sorgfältiger ausgewählt werden, um übermäßige Blockierungen und Konflikte zu vermeiden.
  2. In Situationen, in denen die Datenverteilung relativ gleichmäßig ist und die Konfliktwahrscheinlichkeit gering ist, können relativ einfache und effiziente Methoden verwendet werden, beispielsweise die optimistische Parallelitätskontrolle.

schöne Trennlinie

5. Beispielanalyse

Angenommen, wir haben ein Bestandsverwaltungssystem für einen Online-Shop mit einem inventory Tabelle zum Speichern der Lagerbestandsmengen von Artikeln.

CREATE TABLE inventory (
    product_id INT PRIMARY KEY,
    quantity INT,
    last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
  • 1
  • 2
  • 3
  • 4
  • 5

Es gibt jetzt zwei gleichzeitige Transaktionen:

Transaktion 1:

BEGIN;
SELECT * FROM inventory WHERE product_id = 1;
-- 假设读取到的数量为 10
UPDATE inventory SET quantity = 5 WHERE product_id = 1 AND last_updated <= <read_timestamp>;
COMMIT;
  • 1
  • 2
  • 3
  • 4
  • 5

Transaktion 2:

BEGIN;
SELECT * FROM inventory WHERE product_id = 1;
-- 假设也读取到的数量为 10
UPDATE inventory SET quantity = 8 WHERE product_id = 1 AND last_updated <= <read_timestamp>;
COMMIT;
  • 1
  • 2
  • 3
  • 4
  • 5

Wenn diese beiden Transaktionen nahezu gleichzeitig ausgeführt werden, kann es zu einem Konflikt kommen.

Wenn wir eine zeitstempelbasierte Konfliktlösung verwenden:

  1. Transaktion 1 hat beim Lesen von Daten den aktuellen Zeitstempel erhalten (T1)。
  2. Transaktion 2 erhielt beim Lesen der Daten einen etwas späteren Zeitstempel (T2)。

Wenn Transaktion 1 eine Aktualisierung versucht und keine andere Transaktion die Daten geändert hat, seit sie sie gelesen hat (d. h. last_updated <= T1), ist das Update erfolgreich.

Wenn Transaktion 2 versucht, die Daten zu aktualisieren, werden diese festgestellt last_updated mehr als dieT2(Dies zeigt an, dass es geändert wurde, nachdem Transaktion 2 es gelesen hat.) Die Aktualisierung schlägt fehl und Transaktion 2 kann ein Rollback durchführen und es erneut versuchen oder eine andere Verarbeitung entsprechend der Geschäftslogik durchführen.


schöne Trennlinie

🎉相关推荐

PostgreSQL