Samtidighetskontroll for delta-tabeller

Når flere Fabric-notatbøker, pipelines eller Spark-jobber skriver til samme Delta-tabell samtidig, bruker Delta Lake optimistisk samtidighetskontroll (OCC) for å holde tabellen konsistent. Hver transaksjon leser et øyeblikksbilde, skriver nye filer, og validerer deretter at ingen konfliktfylt commit har skjedd imellom. Hvis en konflikt oppdages, mislykkes transaksjonen med et unntak i stedet for å korrumpere data.

Denne artikkelen dekker praktiske mønstre for å håndtere samtidige skrivinger i Fabric. For en fullstendig spesifikasjon av OCC-protokollen, se Delta Lake samtidighetskontroll (åpen kildekode-dokumentasjon).

Isolasjonsnivåer

Alle Delta-tabeller bruker det serialiserbare isolasjonsnivået. Serializable er det strengeste nivået og det eneste som støttes. Den sikrer at resultatet av samtidige transaksjoner er identisk med en sekvensiell utførelsesrekkefølge.

Delta Lake bruker også et internt SnapshotIsolation-nivå for operasjoner som ikke endrer logiske data (som OPTIMIZE). SnapshotIsolation hopper over sjekken av samtidige appender, slik at komprimering kan fortsette uten å kollidere med samtidige innsettinger. Du konfigurerer ikke SnapshotIsolation direkte – Delta Lake bruker det automatisk når det er hensiktsmessig.

Med Serializable isolasjon kan et samtidig blindt tillegg (INSERT INTO) komme i konflikt med a MERGE eller UPDATE som leser samme partisjon.

Hvilke operasjoner er konflikt

Ikke alle samtidige skrivinger er i konflikt. Den viktigste faktoren er om to operasjoner berører de samme underliggende filene.

Samtidig par Konflikt? Hvorfor
To INSERT (vedlagt) operasjoner Nei Hver legger til nye filer uten å lese eksisterende (blind append).
INSERT + OPTIMIZE Nei OPTIMIZE commits at SnapshotIsolation fordi den ikke endrer logiske data, så den hopper over sjekken av samtidige tillegg helt. Tillegg legger til nye filer som ikke overlapper med filer som komprimeres.
To, UPDATEDELETE, eller MERGE operasjoner Ja, hvis de leser eller endrer overlappende filer Hver skriver om filer, så den andre forfatterens snapshot blir utdatert.
OPTIMIZE + UPDATE/DELETE/MERGE Ja, hvis de berører de samme filene OPTIMIZE fjerner og legger til filer igjen (med dataChange=false). Hvis en datamodifikasjonsoperasjon også leser de samme filene, blir a ConcurrentDeleteReadException hevet.
To OPTIMIZE løp Ja, hvis de velger de samme filene Begge forsøker å fjerne og omskrive det samme settet med filer, noe som utløser en ConcurrentDeleteDeleteException.
INSERT + MERGE/UPDATE/DELETE Ja, hvis dataendringsoperasjonen leser samme partisjon Under Serializable, kan et blind tillegg komme i konflikt med samtidige dataendringer hvis operasjonen leste en partisjon som appenden skrev til.

Tips

Append-only pipelines (INSERT INTO, df.write.mode("append")) er den enkleste måten å unngå konflikter helt på. Hvis arbeidsmengden din kan legges til først og avstemmes senere, eliminerer du skriv-skriv-konflikt.

Isoler skribenter med partisjonering

Den vanligste måten å kjøre samtidig DML mot samme tabell uten konflikter på, er å dele tabellen etter kolonnen som skiller forfatterne dine, og deretter inkludere den kolonnen i hver operasjonsbetingelse. Når hver forfatter retter seg mot en forskjellig partisjon, berører operasjonene disjunkte filsett og kommer ikke i konflikt.

Et typisk scenario: flere pipelines behandler hver data for en annen forretningsenhet eller leietaker. Partisjoner etter den dimensjonen og fest hver rørledning MERGE til sin partisjon.

-- Each pipeline targets its own partition, so concurrent runs don't conflict
MERGE INTO events AS target
USING staged AS source
ON target.event_id = source.event_id
    AND target.business_unit = 'EMEA'
WHEN MATCHED THEN UPDATE SET *
WHEN NOT MATCHED THEN INSERT *

Important

Partisjonskolonnen må vises i selve sammenslåingsbetingelsen—ikke bare i kildedataene. Uten den kan ikke Delta Lake ved validering fastslå at de to operasjonene berørte disjunkte filsett, og konfliktsjekkeren behandler operasjonen som en full-tabell-lesing.

For mer detaljer om partisjoneringsstrategier, se Partitionering for Delta-tabeller.

Innebygd commit retry

Delta Lake prøver automatisk en commit på nytt når den oppdager at en annen transaksjon er gjort først. Ved hvert forsøk leser den vinnende commit, kjører konfliktsjekkeren, og – hvis det ikke finnes noen logisk konflikt – prøver den commit på nytt ved neste tilgjengelige versjon. Denne prosessen gjentas transparent uten noen handling fra koden din.

En logisk konflikt (for eksempel to operasjoner som skriver om samme fil) kan ikke løses automatisk. Gjenprøvingen reiser ett av unntakene listet i Common conflict-unntakene. Mange kollisjoner med forbigående versjoner – som to blinde tillegg som konkurrerer om samme versjonsplass – løses imidlertid automatisk og vises aldri i applikasjonen din.

Vanlige unntak for konflikt

Når en konflikt oppdages, oppretter Delta Lake et spesifikt unntak. Å forstå hvilket unntak du ser hjelper deg å identifisere den egentlige årsaken.

Unntak Hva har skjedd
ConcurrentAppendException En annen forfatter la til filer i en partisjon (eller filsett) som operasjonen din leste. Vanlig når en MERGE kjører mot en partisjon som også mottar inserts fra en annen pipeline. Under Serializable isolasjon kan selv blinde tillegg (vanlige INSERT operasjoner) utløse dette unntaket.
ConcurrentDeleteReadException En annen forfatter slettet eller skrev om en fil som operasjonen din leste. Typisk når OPTIMIZE filer komprimeres som en samtidig UPDATE eller MERGE også leste, eller når to datamodifikasjonsoperasjoner overlapper på de samme radene.
ConcurrentDeleteDeleteException Begge operasjonene forsøkte å slette eller omskrive den samme filen. Ofte forårsaket av overlappende OPTIMIZE kjøringer eller to pipelines som omskriver samme partisjon samtidig.
ConcurrentWriteException En generell konflikt oppstår når en annen transaksjon ble forpliktet til samme tabellversjon før konfliktløsning kunne kjøres—for eksempel under en oppgradering fra filsystem til managed commits.
MetadataChangedException Tabellens skjema eller egenskaper endres midt i en transaksjon ALTER TABLE – for eksempel en samtidig eller skjema-evolusjonsskriving.
ConcurrentTransactionException To Structured Streaming-spørringer med samme sjekkpunktplassering ble skrevet til tabellen samtidig. Dedupliser strømmeoppdragene dine eller bruk ulike sjekkpunkt-veier.
ProtocolChangedException En samtidig transaksjon oppgraderte eller nedgraderte tabellprotokollen mens den nåværende transaksjonen også forsøkte en protokollendring. Kan også oppstå når en tabellfunksjon droppes samtidig.

Vanlige strategier for å unngå skrivekonflikter

Aktiver automatisk komprimering

Automatisk komprimering kjører synkront som en del av skriveoperasjoner. Synkron komprimering forhindrer at separat planlagte komprimeringsjobber overlapper med dataendringsoperasjoner og dermed forårsaker samtidige skriverunntak.

Planlegg vedlikehold utenfor skrivevinduer

OPTIMIZE og VACUUM kan komme i konflikt med samtidige dataendringsoperasjoner. I Fabric, planlegg notatbokjobber eller pipeline-aktiviteter for tabellkompaktering og VACUUM under lavaktivitetsvinduer – for eksempel etter at nattlig inntak er fullført, ikke underveis.

Bruk append + merge-mønstre

For høy-samtidig-inntak, land rådata med kun append-skriving inn i en staging-tabell (ingen konflikter mulig), og kjør deretter en enkelt MERGE jobb for å avstemme til måltabellen. Mønsteret serialiserer den konfliktutsatte operasjonen samtidig som inntaket holdes helt parallelt.

Legg til retry-logikk for logiske konflikter

Den innebygde commit retry håndterer transiente versjonskollisjoner automatisk, men logiske konflikter – der to operasjoner faktisk overlapper hverandre – utløser et unntak. Fordi Delta Lake aldri produserer delvise skrivinger, er en mislykket transaksjon trygg å prøve på nytt på applikasjonsnivå. For pipelines hvor det er forventet sporadiske logiske konflikter, pakk inn skrivelogikken i retry:

from delta.exceptions import ConcurrentAppendException
import time

# Retry with backoff on transient concurrent write conflicts
max_retries = 3
for attempt in range(max_retries):
    try:
        spark.sql("MERGE INTO target USING source ON ...")
        break
    except ConcurrentAppendException:
        if attempt < max_retries - 1:
            time.sleep(2 ** attempt)
        else:
            raise

Velg riktig layoutstrategi

Væskeklynging og partisjonering løser ulike problemer. Liquid clustering optimaliserer filoppsettet for leseytelse. Oppdeling skaper fysiske grenser som forhindrer samtidige konflikter mellom forfattere. Hvis arbeidsmengden din trenger begge deler, partisjoner du etter writer-isolation-kolonnen og bruker Z-Order innenfor hver partisjon for leseytelse.