![Search icon](https://hackernoon.imgix.net/search-new.png?w=19&h=19)
Vybudovanie spoľahlivého, vysoko dostupného, škálovateľného distribuovaného systému si vyžaduje dodržiavanie špecifických techník, princípov a vzorov. Návrh takýchto systémov zahŕňa riešenie nespočetných problémov. Medzi najrozšírenejšie a najzákladnejšie problémy patrí problém duálneho zápisu .
„Problém s duálnym zápisom“ je problém, ktorý vzniká v distribuovaných systémoch, najmä pri práci s viacerými zdrojmi údajov alebo databázami, ktoré je potrebné udržiavať v synchronizácii. Vzťahuje sa na ťažkosti so zabezpečením toho, aby sa zmeny údajov konzistentne zapisovali do rôznych dátových úložísk, ako sú databázy alebo vyrovnávacie pamäte, bez toho, aby sa zaviedli problémy, ako sú nezrovnalosti údajov, konflikty alebo obmedzenia výkonu.
Architektúra mikroslužieb a databáza vzorov na službu vám prináša mnoho výhod, ako je nezávislé nasadenie a škálovanie, izolované zlyhania a potenciálne zvýšenie rýchlosti vývoja. Operácie si však vyžadujú zmeny medzi viacerými mikroslužbami, čo vás núti premýšľať o spoľahlivom riešení na vyriešenie tohto problému.
Uvažujme o scenári, v ktorom naša doména zahŕňa prijímanie žiadostí o úver, ich posudzovanie a následné zasielanie upozornení zákazníkom.
V duchu princípu jedinej zodpovednosti, Conwayovho zákona a prístupu k dizajnu riadenému doménou bola po niekoľkých stretnutiach s udalosťami celá doména rozdelená na tri subdomény s definovaným ohraničeným kontextom s jasnými hranicami, doménovými modelmi a všadeprítomným jazykom.
Prvý má za úlohu nastupovanie a zostavovanie nových žiadostí o úver. Druhý systém vyhodnocuje tieto žiadosti a rozhoduje na základe poskytnutých údajov. Tento proces hodnotenia, vrátane kontroly KYC/KYB, boja proti podvodom a kreditného rizika, môže byť časovo náročný, čo si vyžaduje schopnosť spracovať tisíce žiadostí súčasne. V dôsledku toho bola táto funkcia delegovaná na vyhradenú mikroslužbu s vlastnou databázou, ktorá umožňuje nezávislé škálovanie.
Okrem toho tieto podsystémy riadia dva rôzne tímy, z ktorých každý má svoje vlastné cykly vydávania, zmluvy o úrovni služieb (SLA) a požiadavky na škálovateľnosť.
Nakoniec existuje špecializovaná oznamovacia služba na odosielanie upozornení zákazníkom.
Tu je podrobný popis primárneho prípadu použitia systému:
Je to na prvý pohľad celkom jednoduchý a primitívny systém, ale poďme sa pozrieť na to, ako služba Žiadosť o pôžičku spracováva príkaz na odoslanie žiadosti o pôžičku.
Môžeme zvážiť dva prístupy k interakciám so službami:
First-Local-Commit-Then-Publish: V tomto prístupe služba aktualizuje svoju lokálnu databázu (potvrdí) a potom zverejní udalosť alebo správu iným službám.
First-Publish-Then-Local-Commit: Naopak, táto metóda zahŕňa zverejnenie udalosti alebo správy pred potvrdením zmien do lokálnej databázy.
Obe metódy majú svoje nevýhody a sú len čiastočne bezpečné pre komunikáciu v distribuovaných systémoch.
Toto je sekvenčný diagram aplikácie prvého prístupu.
V tomto scenári služba žiadosti o pôžičku využíva prístup First-Local-Commit-Then-Publish , kde najprv potvrdí transakciu a potom sa pokúsi poslať oznámenie do iného systému. Tento proces však môže zlyhať, ak sa napríklad vyskytnú problémy so sieťou, hodnotiaca služba je nedostupná alebo služba žiadosti o pôžičku narazí na chybu Nedostatok pamäte (OOM) a zlyhá. V takýchto prípadoch by sa správa stratila a hodnotenie by zostalo bez oznámenia o novej žiadosti o pôžičku, pokiaľ sa nezavedú dodatočné opatrenia.
A ten druhý.
V scenári First-Publish-Then-Local-Commit čelí služba žiadosti o pôžičku významnejším rizikám. Môže to informovať hodnotiacu službu o novej aplikácii, ale nedokáže túto aktualizáciu lokálne uložiť kvôli problémom, ako sú problémy s databázou, chyby pamäte alebo chyby v kóde. Tento prístup môže viesť k výrazným nezrovnalostiam v údajoch, čo môže spôsobiť vážne problémy v závislosti od toho, ako služba Loan Review Service narába s prichádzajúcimi žiadosťami.
Preto musíme nájsť riešenie, ktoré ponúka robustný mechanizmus zverejňovania udalostí externým spotrebiteľom. Ale predtým, ako sa ponoríme do potenciálnych riešení, mali by sme si najprv objasniť typy záruk doručovania správ, ktoré je možné dosiahnuť v distribuovaných systémoch.
Existujú štyri typy záruk, ktoré môžeme dosiahnuť.
Žiadne záruky
Neexistuje žiadna záruka, že správa bude doručená na miesto určenia. Presne o tom je prístup First-Local-Commit-Then-Publish . Spotrebitelia môžu dostávať správy raz, viackrát alebo vôbec.
Maximálne raz doručenie
Maximálne raz doručenie znamená, že správa bude doručená na miesto určenia maximálne 1 krát. Prístup First-Local-Commit-Then-Publish možno implementovať týmto spôsobom aj s politikou opakovania pokusov s hodnotou jedna.
Doručenie aspoň raz \ Spotrebitelia prijmú a spracujú každú správu, ale rovnakú správu môžu dostať aj viackrát.
Presne raz doručenie\Presne raz doručenie znamená, že spotrebiteľ dostane správu efektívne raz.
Technicky je možné dosiahnuť transakciami Kafka a špecifickou idempotentnou implementáciou výrobcu a spotrebiteľa.
Vo väčšine prípadov záruky doručenia „aspoň raz“ riešia mnohé problémy zabezpečením doručenia správ aspoň raz, ale spotrebitelia musia byť idempotentní. Avšak vzhľadom na nevyhnutné zlyhania siete musí byť všetka spotrebiteľská logika idempotentná, aby sa zabránilo spracovaniu duplicitných správ, bez ohľadu na záruky výrobcu. Preto táto požiadavka nie je ani tak nevýhodou, ako skôr odráža realitu.
Na tento problém existuje množstvo riešení, ktoré majú svoje výhody aj nevýhody.
Podľa Wikipédie je Two-Phase Commit (2PC) distribuovaný transakčný protokol používaný v informatike a systémoch správy databáz na zabezpečenie konzistentnosti a spoľahlivosti distribuovaných transakcií. Je navrhnutý pre situácie, keď sa na jednej transakcii musia zúčastniť viaceré zdroje (napr. databázy), a zabezpečuje, že buď všetky transakciu potvrdia, alebo ju všetky prerušia, čím sa zachová konzistencia údajov. Znie to presne tak, ako potrebujeme, ale dvojfázový záväzok má niekoľko nevýhod:
Najviditeľnejším riešením pre architektúru mikroslužieb je použiť vzor (alebo dokonca niekedy anti-vzor) – zdieľanú databázu. Tento prístup je veľmi intuitívny, ak potrebujete transakčnú konzistenciu medzi viacerými tabuľkami v rôznych databázach, stačí použiť jednu zdieľanú databázu pre tieto mikroslužby.
Nevýhody tohto prístupu zahŕňajú zavedenie jediného bodu zlyhania, zamedzenie nezávislého škálovania databázy a obmedzenie možnosti používať rôzne databázové riešenia, ktoré sú najvhodnejšie pre špecifické požiadavky a prípady použitia. Okrem toho by na podporu takejto formy distribuovanej transakcie boli potrebné úpravy kódových báz mikroslužieb.
„ Transakčná pošta na odoslanie “ je návrhový vzor používaný v distribuovaných systémoch na zabezpečenie spoľahlivého šírenia správ, dokonca aj v prípade nespoľahlivých systémov zasielania správ. Zahŕňa ukladanie udalostí do určenej tabuľky 'OutboxEvents' v rámci rovnakej transakcie ako samotná operácia. Tento prístup je v súlade s vlastnosťami ACID relačných databáz. Na rozdiel od toho mnohé databázy No-SQL plne nepodporujú vlastnosti ACID a namiesto toho sa rozhodli pre princípy teorému CAP a filozofie BASE, ktoré uprednostňujú dostupnosť a prípadnú konzistentnosť pred prísnou konzistentnosťou.
Transakčná pošta na odoslanie poskytuje aspoň raz záruku a môže byť implementovaná niekoľkými prístupmi:
Chvost denníka transakcií
Vydavateľ prieskumu verejnej mienky
Prístup tailing protokolu transakcií zahŕňa použitie riešení špecifických pre databázu, ako je CDC (Change Data Capture). Hlavné nevýhody tohto prístupu sú:
Databázové špecifické riešenia
Zvýšená latencia v dôsledku špecifík implementácií CDC
Ďalšou metódou je aplikácia Polling Publisher , ktorá uľahčuje vykladanie odosielaných správ prostredníctvom dotazovania v tabuľke odosielaných správ. Hlavnou nevýhodou tohto prístupu je potenciál zvýšeného zaťaženia databázy, čo môže viesť k vyšším nákladom. Okrem toho nie všetky databázy No-SQL podporujú efektívne dopytovanie pre špecifické segmenty dokumentov. Extrahovanie celých dokumentov môže preto viesť k zníženiu výkonu.
Tu je malý sekvenčný diagram vysvetľujúci, ako to funguje.
Primárna výzva pri vzore Transactional Outbox spočíva v jeho závislosti od vlastností databázy ACID. V typických databázach OLTP to môže byť jednoduché, ale predstavuje výzvy v oblasti NoSQL. Na vyriešenie tohto problému je potenciálnym riešením využiť protokol pridania (napríklad Kafka) hneď od spustenia spracovania požiadavky.
Namiesto priameho spracovania príkazu „podať žiadosť o pôžičku“ ho okamžite pošleme do internej Kafkovej témy a potom vrátime klientovi „akceptovaný“ výsledok. Keďže je však veľmi pravdepodobné, že príkaz ešte musí byť spracovaný, nemôžeme zákazníka okamžite informovať o výsledku. Na zvládnutie tejto prípadnej konzistencie môžeme použiť techniky, ako je dlhý dopyt, dopytovanie spustené klientom, optimistické aktualizácie používateľského rozhrania alebo používanie WebSockets alebo Server-Sent Events pre upozornenia. Toto je však úplne odlišná téma, takže sa vráťme k úvodnej téme.
Poslali sme správu na internú Kafkovu tému. Služba žiadosti o pôžičku potom spotrebuje túto správu – rovnaký príkaz, aký dostala od klienta – a začne spracovávať. Po prvé, vykonáva určitú obchodnú logiku; až potom, čo je táto logika úspešne vykonaná a výsledky sú zachované, publikuje nové správy na verejnú Kafkovu tému.
Poďme sa pozrieť na kúsok pseudokódu.
public async Task HandleAsync(SubmitLoanApplicationCommand command, ...) { //First, process business logic var loanApplication = await _loanApplicationService.HandleCommandAsync(command, ...); //Then, send new events to public Kafka topic producer.Send(new LoanApplicationSubmittedEvent(loanApplication.Id)); //Then, commit offset consumer.Commit(); }
Čo ak zlyhá spracovanie obchodnej logiky? Žiadny strach, keďže posun ešte nebol potvrdený, správa sa zopakuje.
Čo ak zlyhá odosielanie nových udalostí Kafkovi? Žiadny strach, keďže obchodná logika je idempotentná, nevytvorí duplicitnú žiadosť o úver. Namiesto toho sa pokúsi znova odoslať správy na verejnú tému Kafka.
Čo ak sa správy odošlú Kafkovi, ale nepodarí sa odovzdanie offsetu? Žiadny strach, keďže obchodná logika je idempotentná, nevytvorí duplicitnú žiadosť o úver. Namiesto toho bude znova posielať správy na verejnú tému Kafka a dúfať, že tento krát bude offsetový záväzok úspešný.
Medzi hlavné nevýhody tohto prístupu patrí pridaná zložitosť spojená s novým štýlom programovania, prípadná konzistentnosť (keďže klient sa hneď nedozvie výsledok) a požiadavka, aby bola celá obchodná logika idempotentná.
Čo je to zdroj udalostí a ako by sa dal použiť tu? Event sourcing je softvérový architektonický vzor, ktorý sa používa na modelovanie stavu systému zachytením všetkých zmien jeho údajov ako série nemenných udalostí. Tieto udalosti predstavujú fakty alebo stavové prechody a slúžia ako jediný zdroj pravdy pre súčasný stav systému. Technicky teda implementáciou systému na získavanie udalostí už máme všetky udalosti v EventStore a tento EventStore môžu spotrebitelia používať ako jediný zdroj pravdy o tom, čo sa stalo. Nie je potrebné špecifické databázové riešenie na sledovanie všetkých zmien alebo obáv z objednávania, jediným problémom je sedieť na čítacej strane, pretože na získanie aktuálneho stavu entity je potrebné prehrať všetky udalosti.
V tomto článku sme zhodnotili niekoľko prístupov k budovaniu spoľahlivého zasielania správ v distribuovaných systémoch. Existuje niekoľko odporúčaní, ktoré by sme mohli zvážiť pri budovaní systémov s týmito vlastnosťami
Nabudúce sa pozrieme na praktickejší príklad implementácie Transakčnej schránky na odoslanie. Pozri
ty!