Nie len spracovanie: Ako sme z Kafka Streams vytvorili distribuovanú databázu a čo z toho vyšlo

Ahoj, Habr!

Pripomíname, že po knihe o Kafke sme vydali nemenej zaujímavú prácu o knižnici Kafka Streams API.

Nie len spracovanie: Ako sme z Kafka Streams vytvorili distribuovanú databázu a čo z toho vyšlo

Kým komunita si iba osvojuje hranice možností tohto mocného nástroja. Nedávno bola vydaná článok, s ktorou sa vám chceme oboznámiť. Na vlastnej skúsenosti autor rozpráva, ako spraviť z Kafka Streams distribuované úložisko dát. Príjemné čítanie!

Knižnica Apache Kafka Streams sa po celom svete používa v podnikoch na distribuované streamové spracovanie nad Apache Kafka. Jedným z prehliadaných aspektov tohto rámca je to, že umožňuje uchovávať lokálny stav generovaný na základe streamového spracovania.

V tomto článku poviem, ako sa našej spoločnosti podarilo výhodne využiť túto možnosť pri vývoji produktu na bezpečnosť cloudových aplikácií. Pomocou Kafka Streams sme vytvorili mikroservisy so zdieľaným stavom, z ktorých každý slúži ako nám odolný a vysoko dostupný zdroj dôveryhodných informácií o stave objektov v systéme. Pre nás je to krok vpred v oblasti spoľahlivosti aj v pohodlí podpory.

Ak vás zaujíma alternatívny prístup, ktorý umožňuje používať jednu centrálnu databázu na podporu formálneho stavu vašich objektov – prečítajte si, bude to zaujímavé…

Prečo sme považovali, že nastal čas zmeniť naše prístupy k práci so zdieľaným stavom

Potrebovali sme udržiavať stav rôznych objektov, spoliehajúc sa na správy agentov (napríklad: bol web napadnutý?). Pred prechodom na Kafka Streams sme sa často spoliehali na riadenie stavu prostredníctvom jednej centrálnej databázy (+ servisného API). Tento prístup má svoje nevýhody: v dátovo intenzívnych situáciách udržanie konzistencie a synchronizácie sa stáva skutočnou výzvou. Databáza sa môže stať úzkym miestom alebo sa nachádzať v stave pretekania a trpieť nepravidelnosťami.

Nie len spracovanie: Ako sme z Kafka Streams vytvorili distribuovanú databázu a čo z toho vyšlo

Ilustrácia 1: typický scenár s delením stavu, ktorý sa vyskytoval pred prechodom na
Kafku a Kafka Streams: agenti oznamujú svoje predpoklady cez API, aktualizovaný stav sa vypočítava cez centrálnu databázu

Predstavujeme Kafka Streams – teraz je jednoduché vytvárať mikroservisy so zdieľaným stavom

Približne pred rokom sme sa rozhodli dôkladne preskúmať naše scenáre práce so zdieľaným stavom, aby sme sa vyrovnali s niektorými problémami. Hneď sme sa rozhodli vyskúšať Kafka Streams – je známo, aký je škálovateľný, vysoko dostupný a odolný, a aké bohaté funkcie streamovania má (vrátane transformácií so zachovaním stavu). Presne to, čo sme potrebovali, nehovoriac o tom, ako zrelý a spoľahlivý systém výmeny správ je v Kafka.

Každý z našich vytvorených mikroservisov so zdieľaným stavom bol postavený na inštancii Kafka Streams s celkom jednoduchou topológiou. Skladala sa z 1) zdroja 2) procesora s trvalým úložiskom kľúčov a hodnôt 3) odtoku:

Nie len spracovanie: Ako sme z Kafka Streams vytvorili distribuovanú databázu a čo z toho vyšlo

Obrázok 2: prednastavená topológia našich streamových inštancií pre mikroservisy so zdieľaným stavom. Upozorňujeme: tu je tiež úložisko, ktoré obsahuje metaúdaje o plánovaní.

Pri tomto novom prístupe agenti zostavujú správy, ktoré sa posielajú do zdrojového topiku, a spotrebitelia – povedzme, služba e-mailových oznámení – prijímajú vypočítaný zdieľaný stav cez odtok (výstupný topik).

Nie len spracovanie: Ako sme z Kafka Streams vytvorili distribuovanú databázu a čo z toho vyšlo

Obrázok 3: nový príklad toku úloh pre scenár so zdieľanými mikroservismi: 1) agent generuje správu, ktorá prichádza do zdrojového topika Kafka; 2) mikroservis so zdieľaným stavom (používajúci Kafka Streams) ju spracováva a zapisuje vypočítaný stav do konečného topika Kafka; po čom 3) spotrebitelia prijímajú nový stav

Hej, toto zabudované úložisko kľúčov a hodnôt je naozaj veľmi užitočné!

Ako sme spomenuli vyššie, naša topológia so zdieľaným stavom obsahuje úložisko kľúčov a hodnôt. Našli sme niekoľko spôsobov jeho využitia, a dva z nich sú popísané nižšie.

Možnosť #1: využitie úložiska kľúčov a hodnôt pri výpočtoch

Naš prvý ukladací priestor pre kľúče a hodnoty obsahoval pomocné údaje, ktoré sme potrebovali pre výpočty. Napríklad v niektorých prípadoch bolo zdieľané stavy definované na základe princípu „väčšiny hlasov“. V úložisku sa mohli uchovávať všetky najnovšie správy agentov o stave určitého objektu. Potom, keď sme dostali novú správu od jedného alebo druhého agenta, mohli sme ju uložiť, extrahovať zo skladu správy všetkých ostatných agentov o stave toho istého objektu a zopakovať výpočty.
Nižšie na ilustrácii 4 je zobrazené, ako sme otvorili prístup k úložisku kľúčov a hodnôt spracovávajúcej metóde procesora, takže bolo možné spracovať novú správu.

Nie len spracovanie: Ako sme z Kafka Streams vytvorili distribuovanú databázu a čo z toho vyšlo

Ilustrácia 4: Otvárame prístup k úložisku kľúčov a hodnôt pre spracovávajúcu metódu procesora (po tomto je v každom scenári pracujúcom so zdieľaným stavom potrebné implementovať metódu doProcess)

Možnosť #2: Vytvorenie CRUD API nad Kafka Streams

Po nastavení nášho základného toku úloh sme sa pokúsili napísať RESTful CRUD API pre naše mikroslužby so zdieľaným stavom. Chceli sme, aby bolo možné extrahovať stav niektorých alebo všetkých objektov, ako aj nastavovať alebo odstraňovať stav objektu (to je užitočné pri podpore serverovej časti).

Na podporu všetkých API Get State, zakaždým, keď sme potrebovali znovu vypočítať stav pri spracovaní, sme ho na dlhú dobu ukladali do zabudovaného ukladacieho priestoru kľúčov a hodnôt. V takom prípade je dosť jednoduché implementovať také API pomocou jediného inštancie Kafka Streams, ako je uvedené v nasledujúcom zozname:

Nie len spracovanie: Ako sme z Kafka Streams vytvorili distribuovanú databázu a čo z toho vyšlo

Ilustrácia 5: Použitie zabudovaného ukladacieho priestoru kľúčov a hodnôt na získanie predpočítaného stavu objektu

Aktualizácia stavu objektu cez API nie je taktiež zložitá. V podstate je na to potrebné len vytvoriť producenta Kafka, a pomocou neho vykonať zápis, v ktorom je zahrnutý nový stav. To zabezpečí, že všetky správy generované prostredníctvom API budú spracovávané presne tak, ako správy od iných producentov (napr. agentov).

Nie len spracovanie: Ako sme z Kafka Streams vytvorili distribuovanú databázu a čo z toho vyšlo

Ilustrácia 6: Stav objektu sa dá nastaviť pomocou producenta Kafka

Malé komplikácie: Kafka má mnoho partií

Naším cieľom bolo rozložiť zaťaženie súvisiace s spracovaním a zlepšiť dostupnosť poskytnutím klastru mikroslužieb so zdieľaným stavom pre každý scenár. Nastavenie bolo veľmi jednoduché: po tom, čo sme nakonfigurovali všetky inštancie tak, aby pracovali so rovnakým ID aplikácie (a s rovnakými servermi na spustenie), prakticky všetko ostatné sa vykonalo automaticky. Taktiež sme určili, že každý vstupný topic bude pozostávať z niekoľkých partícií, aby mohol byť každej inštancii priradený podmnožina týchto partícií.

Rovnako spomeniem, že je tu bežné robiť zálohu úložiska stavov, aby v prípade obnovy po zlyhaní sme mohli preniesť túto kópiu na inú inštanciu. Na každé úložisko stavov v Kafka Streams sa vytvára replikovaný topic s logom zmien (v ktorom sú sledované miestne aktualizácie). Takže Kafka neustále poistuje úložisko stavov. Preto v prípade zlyhania jednej alebo druhej inštancie možno stavy úložiska Kafka Streams rýchlo obnoviť na inej inštancii, kde budú prenesené príslušné partície. Naše testy ukázali, že to trvá len niekoľko sekúnd, aj keď je v úložisku milióny záznamov.

Prechod od jednej mikroslužby so zdieľaným stavom na klaster mikroslužieb nie je tak triviálny, pokiaľ ide o realizáciu Get State API. V novej situácii obsahuje úložisko stavov každej mikroslužby iba časť celkového obrazu (tých objektov, ktorých kľúče boli mapované na konkrétnu partíciu). Museli sme zistiť, na ktorej inštancii sa nachádzal stav požadovaného objektu, a to sme robili na základe metadát prúdov, ako je znázornené nižšie:

Nie len spracovanie: Ako sme z Kafka Streams vytvorili distribuovanú databázu a čo z toho vyšlo

Ilustrácia 7: pomocou metadát prúdov určujeme, z ktorej inštancie žiadať stav požadovaného objektu; podobný prístup bol použitý s GET ALL API

Hlavné zistenia

Úložiská stavov v Kafka Streams de facto môžu slúžiť ako distribuovaná databáza,

  • neustále replikovaná v Kafka
  • Nad takýmto systémom sa ľahko buduje CRUD API
  • Spracovanie viacerých partícií je o niečo zložitejšie
  • Je možné pridať jedno alebo viac skladových miest do streamovacej topológie na uchovávanie pomocných údajov. Takáto možnosť môže byť použitá na:
  • Dlhodobé uchovávanie údajov potrebných na výpočty pri streamovacom spracovaní
  • Dlhodobé uchovávanie údajov, ktoré môžu byť užitočné pri nasledujúcej inicializácii streamovej inštancie
  • mnohých ďalších…

Vďaka týmto a ďalším výhodám je Kafka Streams vynikajúca na podporu globálneho stavu v takej distribuovanej sieti, ako je tá naša. Kafka Streams sa ukázala byť veľmi spoľahlivá v produkcii (od momentu jej nasadenia sme prakticky nestratili správy) a sme presvedčený, že jej možnosti tu nekončia!

Zdroj: habr.com

Kúpte si spoľahlivý hosting pre webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Kúpte si spoľahlivý hosting pre webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster