Váš delta feed ztrácí pozdní commity: postavte spolehlivý kurzor
Jeden řádek dorazil pozdě, protože watermark nebyl hranicí commitu. Projděte selhání a pak definujte pokrytí, hranici, retenci a bezpečné obnovení.
Tady je selhání, které jsem viděl dvakrát, ve dvou různých enginech. Export běží v 10:00 a zaznamená nejvyšší časové razítko poslední změny, které viděl. Jedna transakce, která začala v 09:58, je stále otevřená, commitne v 10:03 a nese časové razítko z doby svého začátku. Další export žádá jen řádky novější než 10:00 a nikdy ji neuvidí. Velikost přenosu byla vynikající a data byla špatná.
Projděte export, který ztratil řádek
Sledujte pořadí událostí, ne SQL. Aplikace zapisuje čas změny řádku při začátku transakce, ne při commitu. Exportér čte watermark podle hodin na zdi, zatímco je transakce stále otevřená. Pak transakce commitne s časem změny starším než uložený watermark. Další dávka konzumenta začíná za watermarkem, takže řádek zůstává za kurzorem a už nikdy nebude vybrán.
Nic nezaznamená chybu, protože nic neselhalo. To dělá tuto třídu chyb drahou: delta feed je rychlý, počty řádků vypadají věrohodně a chybějící řádek se objeví o týdny později jako tiket na rekonciliaci, který nikdo nedokáže reprodukovat.
Sekvenční čísla mají stejný tvar vady z jiného důvodu. Monotónní ID vám říká pořadí, v jakém byly hodnoty přiděleny, ne pořadí, v jakém transakce commitly. Transakce, která si vzala nízké číslo, může commitnout po transakci s vysokým číslem, takže kurzor založený na pořadí přidělení může také nechat díru.
Pět slibů, které feed musí splnit
Než zvolíte přenos, požádejte zdrojový systém o kontrakt s pěti klauzulemi. Pokud nějaká chybí, máte heuristiku, ne feed změn.
- Pokrytí: vložení, aktualizace a smazání, každé se stabilním klíčem potřebným k aplikaci.
- Hranice: co znamená hodnota kurzoru a co obsahuje konzistentní dávka.
- Konzistence: jak se čtou související tabulky bez míchání nekompatibilních stavů zdroje.
- Retence: jak dlouho může odpojený konzument pokračovat ze své uložené pozice.
- Reinicializace: podporovaný plný snapshot pro případ, kdy už ta pozice není platná.
Podporovaný mechanismus může splnit všech pět. Dokumentace SQL Serveru ke sledování změn je jeden konkrétní publikovaný příklad: definuje minimální platnou verzi, zaznamenává smazání i změny a popisuje snapshot transakci, která zahrnuje validaci, zachycení verze a související dotazy na změny. Je to příklad, co od zdroje vyžadovat, ne syntaxe, kterou vložíte do jiného enginu.
Navrhněte kontrolní bod jako součást pipeline
Uložená pozice konzumenta je skutečný stavový stroj, tak ho tak i zapište. Kurzor smí postoupit jen přes workflow, které už dávku aplikovalo a commitlo cílovou transakci.
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
Pokud doručení selže v polovině, rekoncilujte stejnou dávku místo vymýšlení nové pozice zdroje. Opětovné vytěžení s čerstvější horní hranicí je způsob, jak se částečná aplikace stane trvalou mezerou. Zrcadlové pravidlo platí i na druhé straně: idempotentní aplikace v cíli brání duplikátům a nedělá nic pro změnu, kterou vytěžení nikdy nevidělo.
Smazání potřebují záznamy, ne závěry
Porovnávání řádků, které ještě existují, nemůže konzumentovi říct, které klíče zmizely. Zdroj, který nikdy nezaznamenává smazání, vám nechá dvě nedokonalé možnosti: držet historii klíčů dost dlouho na diff, nebo spouštět výslovnou plnou rekonciliaci podle plánu. Obě jsou designová rozhodnutí s cenou a žádné neexistuje, dokud ho někdo nevlastní.
Retence je stejný druh rozhodnutí. Každý podporovaný feed změn má okno; uveďte ho v kontraktu a varujte, když se kontrolní bod konzumenta přiblíží. Konzument, který se probudí po dvoutýdenním výpadku, má číst jasnou chybu "nutná reinicializace", ne tiše dostat částečnou dávku.
Pak změřte, jestli se delta vyplatila
Vrátit se k porovnávání každého klíče a hashe je někdy správné a stojí za to vědět, kolik to stojí. Stále přenášíte informace o každém řádku, hashe vám nedají konzistentní snapshot napříč tabulkami a hash schéma přináší vlastní otázky o reprezentaci a kolizích. Méně bajtů s ověřitelnou hranicí je cíl; méně bajtů, které tiše zahodí commitnutou změnu, není žádná delta.
Sloupec poslední změny je nápověda. Kurzor, který přežije pozdní commit, smazání a dlouhý výpadek, je kontrakt.