Vaš delta feed propušta kasne commitove: izgradite pouzdan kursor
Jedan red je stigao kasno jer vodeni žig nije bio granica commita. Prođite kroz grešku, pa definišite pokrivenost, granicu, zadržavanje i siguran nastavak.
Evo greške koju sam vidio dva puta, u dva različita motora. Eksport 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 eksport 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 eksport 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. Eksporter čita vodeni žig po zidnom satu dok je ta transakcija još otvorena. Zatim se transakcija commit-a s vremenom izmjene starijim od sačuvanog 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 sedmicama kasnije kao tiket za usklađivanje koji niko 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 sistema 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: šta znači vrijednost kursora i šta sadrži konzistentan batch.
- Konzistentnost: kako se povezane tabele čitaju bez miješanja nekompatibilnih stanja izvora.
- Zadržavanje: koliko dugo isključeni potrošač može nastaviti sa svoje sačuvane 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 obuhvata validaciju, snimanje verzije i povezane upite promjena. To je primjer šta treba tražiti od izvora, a ne sintaksa koju možete zalijepiti u drugi motor.
Dizajnirajte kontrolnu točku kao dio pipeline-a
Sačuvana 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 jeste način na koji djelimič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
Upoređ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 historiju 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 neko 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 dvosedmičnog prekida treba pročitati jasnu grešku "potrebna je reinicijalizacija", a ne tiho primiti djelimičan batch.
Zatim izmjerite da li je delta bila vrijedna
Vraćanje na upoređivanje svakog ključa i heša ponekad je ispravno i vrijedi znati koliko košta. I dalje prenosite informacije o svakom redu, heševi vam ne daju konzistentan snapshot kroz tabele, a heš 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.