Lūk, kļūme, ko esmu redzējis divreiz, divos dažādos dzinējos. Eksports darbojas 10:00 un ieraksta augstāko redzēto pēdējās izmaiņas laika zīmogu. Viena transakcija, kas sākās 09:58, joprojām ir atvērta, commitējas 10:03 un nes laika zīmogu no sava sākuma brīža. Nākamais eksports pieprasa tikai rindas, kas jaunākas par 10:00, un nekad to neredz. Pārsūtīšanas apjoms bija lielisks, bet dati bija nepareizi.

Izsekojiet eksportam, kas pazaudēja rindu

Izsekojiet notikumu secībai, nevis SQL. Lietotne ieraksta rindas izmaiņas laiku transakcijas sākumā, nevis commit brīdī. Eksportētājs nolasa sienas pulksteņa ūdenszīmi, kamēr transakcija vēl ir atvērta. Pēc tam transakcija commitējas ar izmaiņu laiku, kas ir vecāks par saglabāto ūdenszīmi. Patērētāja nākamā partija sākas pēc ūdenszīmes, tāpēc rinda paliek aiz kursora un nekad vairs netiks izvēlēta.

Nekas neieraksta kļūdu, jo nekas neizgāzās. Tas padara šo kļūdu klasi dārgu: delta plūsma ir ātra, rindu skaits izskatās ticams, un trūkstošā rinda parādās nedēļas vēlāk kā saskaņošanas biļete, ko neviens nevar reproducēt.

Secības numuriem ir tāda pati defekta forma cita iemesla dēļ. Monotonisks ID pasaka vērtību piešķiršanas secību, nevis transakciju commit secību. Transakcija, kas paņēma zemu numuru, var commitēties pēc tās, kas paņēma augstu, tāpēc kursors, kas balstīts uz piešķiršanas secību, arī var atstāt caurumu.

Pieci solījumi, kas plūsmai jāizpilda

Pirms izvēlaties transportu, pieprasiet avota sistēmai līgumu ar piecām klauzulām. Ja kāda klauzula trūkst, jums ir heiristika, nevis izmaiņu plūsma.

  • Pārklājums: ievietojumi, atjauninājumi un dzēšanas, katrs ar stabilu atslēgu, kas nepieciešama tā piemērošanai.
  • Robeža: ko nozīmē kursora vērtība un ko satur konsekventa partija.
  • Konsekvence: kā tiek lasītas saistītās tabulas, nesajaucot nesaderīgus avota stāvokļus.
  • Saglabāšana: cik ilgi atvienots patērētājs var turpināt no saglabātās pozīcijas.
  • Reinicializācija: atbalstīts pilns momentuzņēmums, kad šī pozīcija vairs nav derīga.

Atbalstīts mehānisms var apmierināt visus piecus. SQL Server izmaiņu izsekošanas dokumentācija ir viens konkrēts publicēts piemērs: tā definē minimālo derīgo versiju, reģistrē dzēšanas un izmaiņas, un apraksta momentuzņēmuma transakciju, kas aptver validāciju, versijas tveršanu un saistītos izmaiņu vaicājumus. Tas ir piemērs tam, ko prasīt no avota, nevis sintakse, ko ielīmēt citā dzinējā.

Projektējiet kontrolpunktu kā cauruļvada daļu

Patērētāja saglabātā pozīcija ir īstā stāvokļa mašīna, tāpēc tā arī rakstiet. Kursors drīkst virzīties uz priekšu tikai caur darbplūsmu, kas jau ir piemērojusi partiju un commitējusi mērķa 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

Ja piegāde neizdodas pusceļā, saskaņojiet to pašu partiju, nevis izdomājiet jaunu avota pozīciju. Atkārtota izgūšana ar svaigāku augšējo robežu ir ceļš, kā daļēja piemērošana kļūst par pastāvīgu plaisu. Spoguļa noteikums darbojas arī otrā pusē: idempotenta piemērošana mērķī novērš dublikātus un neko nedara izmaiņai, ko izgūšana nekad nav redzējusi.

Dzēšanām vajag ierakstus, nevis secinājumus

Vēl eksistējošu rindu salīdzināšana nevar pateikt patērētājam, kuras atslēgas pazuda. Avots, kas nekad neieraksta dzēšanas, atstāj divas nepilnīgas iespējas: turēt atslēgu vēsturi pietiekami ilgi diff'am vai pēc grafika palaist skaidru pilnu saskaņošanu. Abi ir dizaina lēmumi ar izmaksām, un neviena nav, ja kāds to nepārvalda.

Saglabāšana ir tāda paša veida lēmums. Katrai atbalstītajai izmaiņu plūsmai ir logs; deklarējiet to līgumā un brīdiniet, kad patērētāja kontrolpunkts tam tuvojas. Patērētājam, kas pamostas pēc divu nedēļu pārtraukuma, vajadzētu lasīt skaidru kļūdu "nepieciešama reinicializācija", nevis klusi saņemt daļēju partiju.

Pēc tam izmēriet, vai delta bija tā vērta

Atgriešanās pie katras atslēgas un jaucējvērtības salīdzināšanas dažkārt ir pareiza, un ir vērts zināt, cik tas izmaksā. Jūs joprojām pārsūtāt informāciju par katru rindu, jaucējvērtības nedod konsekventu momentuzņēmumu starp tabulām, un jaucējvērtību shēma nes savus jautājumus par attēlojumu un sadursmēm. Mazāk baitu ar pārbaudāmu robežu ir mērķis; mazāk baitu, kas klusi nomet commitētu izmaiņu, nemaz nav delta.

Pēdējās izmaiņas kolonna ir mājiens. Kursors, kas pārdzīvo vēlu commit'u, dzēšanu un ilgu pārtraukumu, ir līgums.

Saistītie raksti