Evo greške koju sam vidio dva puta, u dva različita motora. Izvoz se pokreće u 10:00 i bilježi najviši vremenski pečat zadnje izmjene koji je vidio. Jedna transakcija koja je počela u 09:58 još je otvorena, commit-a se u 10:03 i nosi vremenski pečat iz trenutka kada je počela. Sljedeći izvoz traži samo redove novije od 10:00 i nikada je ne vidi. Veličina prijenosa bila je odlična, a podaci pogrešni.

Prođite kroz izvoz koji je izgubio red

Pratite redoslijed događaja, a ne SQL. Aplikacija upisuje vrijeme izmjene reda kada transakcija počne, a ne kada se commit-a. Izvoznik čita vodeni žig po zidnom satu dok je ta transakcija još otvorena. Zatim se transakcija commit-a s vremenom izmjene starijim od spremljenog vodenog žiga. Sljedeći batch potrošača počinje nakon vodenog žiga, pa red ostaje iza kursora i nikada više neće biti odabran.

Ništa ne bilježi grešku jer ništa nije palo. To ovu klasu bugova čini skupom: delta feed je brz, brojevi redova izgledaju uvjerljivo, a red koji nedostaje ispliva tjednima kasnije kao tiket za usklađivanje koji nitko ne može reproducirati.

Redni brojevi imaju isti oblik mane iz drugog razloga. Monotoni ID govori vam redoslijed kojim su vrijednosti dodijeljene, ne redoslijed kojim su se transakcije commit-ale. Transakcija koja je uzela nizak broj može se commit-ati nakon one koja je uzela visok, pa i kursor zasnovan na redoslijedu dodjele može ostaviti rupu.

Pet obećanja koja feed mora dati

Prije nego odaberete transport, tražite od izvornog sustava ugovor s pet klauzula. Ako bilo koja klauzula nedostaje, imate heuristiku, a ne feed promjena.

  • Pokrivenost: umetanja, izmjene i brisanja, svako sa stabilnim ključem potrebnim za primjenu.
  • Granica: što znači vrijednost kursora i što sadrži konzistentan batch.
  • Konzistentnost: kako se povezane tablice čitaju bez miješanja nekompatibilnih stanja izvora.
  • Zadržavanje: koliko dugo isključeni potrošač može nastaviti sa svoje spremljene pozicije.
  • Reinicijalizacija: podržan potpuni snapshot za slučaj kada ta pozicija više nije važeća.

Podržan mehanizam može zadovoljiti svih pet. Dokumentacija SQL Servera o praćenju promjena jedan je konkretan objavljen primjer: definira minimalnu važeću verziju, bilježi brisanja kao i promjene i opisuje snapshot transakciju koja obuhvaća validaciju, snimanje verzije i povezane upite promjena. To je primjer što treba tražiti od izvora, a ne sintaksa koju možete zalijepiti u drugi motor.

Dizajnirajte kontrolnu točku kao dio pipeline-a

Spremljena pozicija potrošača prava je state machine, pa je tako i zapišite. Kursor može napredovati samo kroz workflow koji je već primijenio batch i commit-ao ciljnu transakciju.

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

Ako dostava padne na pola, uskladite isti batch umjesto da izmišljate novu poziciju izvora. Ponovno izvlačenje sa svježijom gornjom granicom jest način na koji djelomična primjena postaje trajna praznina. Zrcalno pravilo vrijedi i s druge strane: idempotentna primjena na cilju sprječava duplikate i ništa ne čini za promjenu koju izvlačenje nikada nije vidjelo.

Brisanja traže zapise, ne zaključke

Uspoređivanje redova koji još postoje ne može reći potrošaču koji su ključevi nestali. Izvor koji nikada ne bilježi brisanja ostavlja vam dvije nesavršene opcije: držati povijest ključeva dovoljno dugo za diff ili pokretati eksplicitno potpuno usklađivanje po rasporedu. Oba su dizajnerske odluke s cijenom, i nijedna ne postoji ako je netko ne posjeduje.

Zadržavanje je ista vrsta odluke. Svaki podržani feed promjena ima prozor; navedite ga u ugovoru i upozorite kada se kontrolna točka potrošača približi njemu. Potrošač koji se probudi nakon dvotjednog prekida treba pročitati jasnu grešku "potrebna je reinicijalizacija", a ne tiho primiti djelomičan batch.

Zatim izmjerite je li delta bila vrijedna

Vraćanje na uspoređivanje svakog ključa i hasha ponekad je ispravno i vrijedi znati koliko košta. I dalje prenosite informacije o svakom redu, hashevi vam ne daju konzistentan snapshot kroz tablice, a hash shema nosi vlastita pitanja o reprezentaciji i kolizijama. Manje bajtova s provjerljivom granicom je cilj; manje bajtova koji tiho ispuste commit-anu promjenu nije nikakva delta.

Kolona zadnje izmjene je nagovještaj. Kursor koji preživi kasan commit, brisanje i dug prekid je ugovor.

Povezani članci