Teknologian jakaminen

Kuinka käsitellä ristiriitojen ratkaisua samanaikaisten tietojen päivitysten yhteydessä PostgreSQL:ssä?

2024-07-12

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

kaunis jakoviiva

PostgreSQL


Tietokannan samanaikaisessa toimintaympäristössä useat tapahtumat, jotka yrittävät päivittää samoja tietoja samanaikaisesti, voivat aiheuttaa ristiriitoja. PostgreSQL tarjoaa joukon mekanismeja näiden samanaikaisten päivitysristiriitojen käsittelemiseksi tietojen johdonmukaisuuden ja eheyden varmistamiseksi.

kaunis jakoviiva

1. Samanaikaiset päivitysristiriidat

Samanaikaisia ​​päivitysristiriitoja voi ilmetä, kun kaksi tai useampi tapahtuma yrittää muokata samaa tietoriviä samanaikaisesti. Yleisiä skenaarioita ovat:

  1. Muokkaa saman rivin eri sarakkeita samanaikaisesti
  2. Päivitä saman sarakkeen eri arvot samanaikaisesti

kaunis jakoviiva

2. Samanaikaisuuden ohjausmekanismi PostgreSQL:ssä

PostgreSQL käyttää pääasiassa MVCC:tä (Multiversion Concurrency Control) käsittelemään samanaikaisia ​​tapahtumia. MVCC sallii tapahtuman lukea dataversion, joka täyttää sen eristystason vaatimukset ilman lukitusta muiden tapahtumien lukutoimintojen estämiseksi. Ristiriitoja saattaa kuitenkin esiintyä kirjoitustoimintojen aikana.

(1) Lukitusmekanismi

PostgreSQL käyttää useita erityyppisiä lukkoja hallitakseen samanaikaista pääsyä tietoihin. Yleisiä lukkotyyppejä ovat:

  1. Jaettu lukko: Sallii muiden tapahtumien hankkia jaettuja lukkoja, mutta estää eksklusiivisten lukkojen hankinnan. Käytetään yleisesti lukutoimintoihin.
  2. Ainutlaatuinen lukko: Estää muita tapahtumia hankkimasta minkään tyyppistä lukitusta, jota käytetään usein kirjoitustoimintoihin.

Lukitustarkkuus voi olla rivitason (Row-Level), sivutason (Page-Level) ja taulukkotason (Table-Level).

(2) Tapahtuman eristystaso

PostgreSQL tukee neljää tapahtuman eristystasoa:

  1. Lue Sitoutumaton: Tämä on alin eristystaso. Tapahtuma voi lukea muiden tapahtumien sitomattomia tietomuokkauksia, jotka voivat johtaa ongelmiin, kuten likaisiin lukemiin, ei-toistuviin lukuihin ja haamulukuihin.
  2. Lue Sitoutunut: Tapahtumat voivat lukea vain lähetettyjä tietoja välttäen likaisia ​​lukuja, mutta ei-toistettavia lukuja ja haamulukuja voi silti tapahtua.
  3. Toistettava luku: Saman datan lukeminen useita kertoja tapahtuman aikana saa saman tuloksen välttäen ei-toistettavia lukuja, mutta haamulukuja voi tapahtua.
  4. Sarjasoitavissa: Korkein eristystaso, joka varmistaa tapahtumien sarjasuorituksen tiukan samanaikaisuuden valvonnan avulla, välttäen likaisia ​​lukuja, ei-toistettavia lukuja ja haamulukuja.

kaunis jakoviiva

3. Samanaikaisten päivitysristiriitojen ratkaisu

(1) Uudelleenyritysmekanismi

Yksinkertainen tapa on saada tapahtuma yrittää uudelleen, kun ristiriita ilmenee. Esimerkkejä ovat seuraavat:

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

Yllä olevassa esimerkissä, jos päivitystoiminto ei vaikuta mihinkään riveihin (osoittaa, että saattaa olla ristiriita), lippu asetetaan, odottaa jonkin aikaa ja yrittää sitten uudelleen.

(2) Käytä optimistista samanaikaisuuden ohjausta

Optimistinen samanaikaisuuden hallinta olettaa, että samanaikaisuusristiriitoja esiintyy harvoin. Tässä menetelmässä tapahtuma ei lukkiudu tietoja päivitettäessä, vaan tarkistaa, ovatko tiedot muuttuneet muiden tapahtumien toimesta sitoutumisen yhteydessä. Jos ristiriitoja ei ole, tapahtuma toteutetaan onnistuneesti, jos on ristiriitoja, tapahtuma peruutetaan ja sitä yritetään tarvittaessa uudelleen.

-- 获取数据的初始版本
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

Yllä olevassa esimerkissä päivitystoiminto onnistuu vain, jos tietoja ei ole muokattu muilla tapahtumilla.

(3) Käytä pessimististä samanaikaisuuden ohjausta

Pessimistinen samanaikaisuuden hallinta olettaa, että samanaikaisuusristiriidat ovat todennäköisiä, ja hankkii tarvittavat lukot tapahtuman suorittamisen aikana estääkseen muut mahdollisesti ristiriitaiset tapahtumat.

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) Sovellusversio-kenttä

Lisää taulukkoon versiokenttä tietojen muutosten seuraamiseksi.

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

Kun päivität tietoja, lisää myös versiokenttää:

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

Jos päivityksen vaikuttavien rivien määrä on 0, kyseessä on ristiriita, koska odotettu versio ei ole yhdenmukainen todellisen version kanssa.

(5) Aikaleimaan perustuva konfliktinratkaisu

Lisää aikaleimakenttä jokaiselle tietoriville tallentaaksesi tietojen viimeisen muokkausajan.

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

Päivittäessäsi päivitä vain tiedot, joiden aikaleima on vanhempi kuin nykyisen tapahtuman lukema aikaleima:

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

kaunis jakoviiva

4. Käytännön sovelluksissa huomioitavaa

(1) Vaikutus suorituskykyyn

  1. Eri konfliktinratkaisumenetelmillä on erilaisia ​​vaikutuksia tietokannan suorituskykyyn. Esimerkiksi eston käyttö voi saada muut tapahtumat odottamaan, pidentää järjestelmän estoaikaa ja siten vaikuttaa samanaikaisuuteen. Optimistinen samanaikaisuuden hallinta toimii paremmin, kun ristiriitoja esiintyy harvoin, mutta kun ristiriitoja esiintyy usein, se voi johtaa suureen määrään tapahtuman uudelleenyrityksiä, mikä pidentää yleistä suoritusaikaa.
  2. Versiokenttien tai aikaleimapohjaisten menetelmien käyttäminen saattaa vaatia lisää tallennustilaa versio- tai aikaleimatietojen ylläpitämiseen ja lisäarviointiin ja -käsittelyyn päivityksen aikana.

(2) Liiketoimintalogiikan mukautumiskyky

  1. Tietyt liiketoimintaskenaariot voivat olla sopivampia tietylle konfliktinratkaisumenetelmälle. Jos yrityksellä on esimerkiksi erittäin korkeat vaatimukset tietojen johdonmukaisuudelle ja se ei voi sietää epäjohdonmukaisuuksia, pessimistinen samanaikaisuuden hallinta tai serialisoinnin eristystaso voi olla parempi valinta.
  2. Optimistinen samanaikaisuuden hallinta saattaa olla sopivampi skenaarioihin, joissa ristiriidat ovat harvempia ja vasteaikavaatimukset ovat korkeammat.

(3) Tiedon jakelu- ja käyttötavat

  1. Jos tietojen käyttö on erittäin samanaikaista ja useat tapahtumat käyttävät usein samoja tietorivejä samanaikaisesti, ristiriitojen ratkaisumenetelmät on valittava huolellisemmin liiallisten estojen ja ristiriitojen välttämiseksi.
  2. Tilanteisiin, joissa tiedon jakautuminen on suhteellisen tasaista ja konfliktin todennäköisyys pieni, voidaan käyttää suhteellisen yksinkertaisia ​​ja tehokkaita menetelmiä, kuten optimistista samanaikaisuuden ohjausta.

kaunis jakoviiva

5. Esimerkkianalyysi

Oletetaan, että meillä on varastonhallintajärjestelmä verkkokaupalle, jossa on a inventory taulukko tavaroiden varastomäärien tallentamiseen.

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

Nyt on kaksi samanaikaista tapahtumaa:

Tapahtuma 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

Tapahtuma 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

Jos nämä kaksi tapahtumaa suoritetaan lähes samaan aikaan, voi syntyä ristiriita.

Jos käytämme aikaleimapohjaista konfliktinratkaisua:

  1. Tapahtuma 1 sai nykyisen aikaleiman luettaessa tietoja (T1)。
  2. Tapahtuma 2 sai hieman myöhemmän aikaleiman dataa luettaessa (T2)。

Kun tapahtuma 1 yrittää päivittää, jos mikään muu tapahtuma ei ole muuttanut tietoja sen lukemisen jälkeen (esim. last_updated <= T1), päivitys onnistui.

Kun tapahtuma 2 yrittää päivittää, jos se havaitsee, että tiedot last_updated enemmän kuinT2(Ilmoittaa, että sitä on muokattu tapahtuman 2 lukemisen jälkeen), päivitys epäonnistuu ja tapahtuma 2 voi peruuttaa ja yrittää uudelleen tai suorittaa muun käsittelyn liiketoimintalogiikan mukaisesti.


kaunis jakoviiva

🎉相关推荐

PostgreSQL