Her er ein feil eg har sett skje to gonger, i to ulike motorar. Ein eksport køyrer klokka 10:00 og registrerer det høgaste tidsstempelet for siste endring han såg. Éin transaksjon som byrja klokka 09:58 er framleis open, committar klokka 10:03 og ber eit tidsstempel frå då han starta. Den neste eksporten ber berre om rader nyare enn 10:00 og ser han aldri. Overføringsstorleiken var framifrå, og dataa var feil.

Følg eksporten som mista ei rad

Følg rekkjefølgja av hendingar i staden for SQL-en. Applikasjonen skriv endringstida til rada når transaksjonen byrjar, ikkje når han committar. Eksportøren les eit veggur-vassmerke medan transaksjonen framleis er open. Deretter committar transaksjonen med ei endringstid som er eldre enn det lagra vassmerket. Den neste batchen til forbrukaren startar etter vassmerket, så rada ligg bak cursoren og vil aldri bli vald igjen.

Ingenting loggar ein feil, fordi ingenting feila. Det er dette som gjer denne feilklassen dyr: delta-feeden er rask, radtalet ser rimeleg ut, og den manglande rada dukkar opp veker seinare som ein avstemmingsbillett ingen kan gjenskape.

Sekvensnummer har same forma for feil av ein annan grunn. Ein monoton ID fortel deg rekkjefølgja verdiane vart tildelte i, ikkje rekkjefølgja transaksjonane committa i. Ein transaksjon som tok eit lågt nummer kan committe etter ein som tok eit høgt nummer, så ein cursor basert på tildelingsrekkjefølgje kan også etterlate eit hol.

Fem løfte feeden må gje

Før du vel transport, be kjeldesystemet om ein kontrakt med fem klausular. Manglar nokon klausul, har du ein heuristikk og ikkje ein endringsfeed.

  • Dekning: innsetjingar, oppdateringar og slettingar, kvar med den stabile nøkkelen som trengst for å bruke han.
  • Grense: kva ein cursorverdi tyder og kva ein konsistent batch inneheld.
  • Konsistens: korleis relaterte tabellar blir lesne utan å blande inkompatible kjeldetilstandar.
  • Oppbevaring: kor lenge ein fråkopia forbrukar kan ta opp att frå den lagra posisjonen sin.
  • Reinitialisering: eit støtta fullt augeblinksbilete for når den posisjonen ikkje lenger er gyldig.

Ein støtta mekanisme kan oppfylle alle fem. Dokumentasjonen til SQL Server om endringssporing er eitt konkret publisert døme: han definerer ein minste gyldig versjon, registrerer slettingar så vel som endringar og skildrar ein augeblinksbiletetransaksjon som spenner over validering, versjonsfangst og dei relaterte endringsspurnadene. Det er eit døme på kva du bør krevje av ei kjelde, ikkje syntaks du kan lime inn i ein annan motor.

Design sjekkpunktet som ein del av pipelinen

Den lagra posisjonen til forbrukaren er den eigentlege tilstandsmaskinen, så skriv han som det. Cursoren kan berre gå framover gjennom arbeidsflyten som allereie har brukt batchen og committa måltransaksjonen.

cursor  = durable_checkpoint()          # last fully applied position
batch   = extract(cursor, upper_bound)  # one consistent batch
apply(batch)                            # idempotent at the target
commit()
checkpoint(batch.upper_bound)           # only now

Viss leveringa feilar halvvegs, avstem den same batchen i staden for å finne opp ein ny kjeldeflate. Å trekkje ut på nytt med ei friskare øvre grense er måten ein delvis bruk blir eit permanent hol. Spegelregelen gjeld også på den andre sida: idempotent bruk ved målet hindrar duplikat og gjer ingenting for ei endring som uttrekket aldri såg.

Slettingar treng registreringar, ikkje konklusjonar

Å samanlikne rader som framleis finst kan ikkje fortelje ein forbrukar kva nøklar som forsvann. Ei kjelde som aldri registrerer slettingar, lèt deg sitje med to ufullkomne val: halde ein nøkkelhistorikk lenge nok til å diffe mot, eller køyre ei eksplisitt full avstemming etter ein plan. Begge er designval med ein kostnad, og ingen av dei finst med mindre nokon eig han.

Oppbevaring er same slags avgjerd. Kvar støtta endringsfeed har eit vindauge; oppgje det i kontrakten og varsle når sjekkpunktet til ein forbrukar nærmar seg det. Ein forbrukar som vaknar etter eit avbrot på to veker, bør lese ein tydeleg feil "reinitialisering krevst" i staden for stille å ta imot ein delvis batch.

Mål deretter om deltaen var verdt det

Å falle tilbake på å samanlikne kvar nøkkel og hash er nokre gonger rett, og det er verdt å vite kva det kostar. Du overfører framleis informasjon om kvar rad, hashar gjev deg ikkje eit konsistent augeblinksbilete på tvers av tabellar, og eit hashskjema bringar sine eigne spørsmål om representasjon og kollisjonar. Færre byte med ei stadfestande grense er målet; færre byte som stille slepp ei committa endring er ikkje nokon delta i det heile.

Ein kolonne for siste endring er eit hint. Ein cursor som overlever ein sein commit, ei sletting og eit langt avbrot, er ein kontrakt.

Relaterte artiklar