Përshëndetje, Habr!
Ju kujtojmë se pas librit për ne kemi nxjerrë një vepër të tjera interesante për bibliotekën .

Ndërkohë që komuniteti po zbret në kufijtë e mundësive të këtij mjeti të fuqishëm. Së fundmi, u publikua një artikull, me përkthimin e të cilit dëshirojmë t'ju njohim. Autori, përmes përvojës së tij, tregon se si të krijosh një depo të shpërndarë të të dhënave nga Kafka Streams. Lexim të këndshëm!
Biblioteka Apache përdoret në mbarë botën në ndërmarrje për procesimin e shpërndarë të flukseve mbi Apache Kafka. Një nga aspektet e nënvlerësuara të këtij framework-u është se ai lejon ruajtjen e një gjendjeje lokale, e cila prodhohet në bazë të përpunimit të flukseve.
Në këtë artikull, do të flas për mënyrën sesi në kompaninë tonë arritëm të përfitojmë nga kjo mundësi gjatë zhvillimit të një produkti për sigurinë e aplikacioneve në re. Me ndihmën e Kafka Streams, ne krijuam mikroshërbime me gjendje të ndarë, secili prej të cilëve na shërben si një burim i qëndrueshëm dhe me disponueshmëri të lartë të informacionit të besueshëm mbi gjendjen e objekteve në sistem. Për ne, kjo është një përparësi sa në aspektin e qëndrueshmërisë, ashtu edhe në përmirësimin e mbështetjes.
NĂ«se jeni tĂ« interesuar pĂ«r njĂ« qasje alternative qĂ« lejon pĂ«rdorimin e njĂ« baze tĂ« dhĂ«nash qendrore pĂ«r tĂ« mbĂ«shtetur gjendjen formale tĂ« objekteve tuaj â lexoni, do tĂ« jetĂ« interesanteâŠ
Pse e konsideruam se ka ardhur koha për të ndryshuar qasjet tona në punën me gjendjen e ndarë
Na duheshin mbështetje për gjendjen e objekteve të ndryshme, duke u mbështetur në raportet e agenëve (p.sh.: a është sulmuar site-i)? Para kalimit në Kafka Streams, shpesh kemi varur menaxhimin e gjendjes nga një bazë të dhënash qendrore (+ API shërbimi). Ky qasje ka disa disavantazhe: në mbështetje për konsistencën dhe sinkronizimin bëhet një sfidë e vërtetë. Baza e të dhënave mund të bëhet nyja e ngushtë, ose të ndodhet në dhe të përbalet me papërcaktueshmërinë.

Ilustrimi 1: një skenar tipik me ndarje të gjendjes, që ndodhi para kalimit në
Kafka dhe Kafka Streams: agentët raportojnë përmbledhjet e tyre përmes API-së, gjendja e azhurnuar llogaritet përmes një baze të dhënash qendrore
Njoftohuni me Kafka Streams â tani Ă«shtĂ« bĂ«rĂ« e lehtĂ« tĂ« krijoni mikrosĂ«rvime me gjendje tĂ« ndarĂ«
Rreth njĂ« vit mĂ« parĂ«, ne vendosĂ«m tĂ« rishikojmĂ« me kujdes skenarĂ«t tanĂ« pĂ«r menaxhimin e gjendjes sĂ« ndarĂ« pĂ«r tĂ« trajtuar disa probleme. MenjĂ«herĂ« vendosĂ«m tĂ« provonim Kafka Streams â dihet se sa e shkallĂ«zueshme, e disponueshme dhe e qĂ«ndrueshme Ă«shtĂ«, si dhe sa e pasur Ă«shtĂ« me funksionalitete pĂ«r pĂ«rpunim rrjedhash (transformime, pĂ«rfshirĂ« ato me ruajtjen e gjendjes). PikĂ«risht ajo qĂ« na nevojitej, pa pĂ«rmendur se sa e pjekur dhe e besueshme Ă«shtĂ« sistemi i dĂ«rgimit tĂ« mesazheve nĂ« Kafka.
Ădo njĂ« nga shĂ«rbimet mikro qĂ« krijuam me ruajtjen e gjendjes u ndĂ«rtua mbi njĂ« instancĂ« tĂ« Kafka Streams me njĂ« topologji mjaft tĂ« thjeshtĂ«. Ajo pĂ«rbĂ«hej nga 1) burimi 2) procesori me njĂ« magazinĂ« tĂ« vazhdueshme tĂ« çelĂ«save dhe vlerave 3) rrjedha:

Ilustrimi 2: topologjia e paracaktuar e instancave tona të rrjedhave për shërbimet mikro me ruajtjen e gjendjes. Vini re: këtu ka gjithashtu një magazinë ku ruhen metadat për planifikimin.
Me kĂ«tĂ« qasje tĂ« re, agjentĂ«t formulojnĂ« mesazhe qĂ« dĂ«rgohen nĂ« temĂ«n e origjinĂ«s, ndĂ«rsa konsumatorĂ«t â le tĂ« themi, shĂ«rbimi i njoftimeve pĂ«rmes postĂ«s â marrin gjendjen e llogaritur tĂ« ndarĂ« pĂ«rmes koleksionit (temĂ«s sĂ« daljes).

Ilustrimi 3: një shembuj i ri i fluksit të detyrave për skenarë me mikroshërbime të ndara: 1) agjenti krijon një mesazh që arrin në temën e origjinës Kafka; 2) mikroshërbimi me gjendje të ndarë (duke përdorur Kafka Streams) e proceson atë dhe regjistron gjendjen e llogaritur në temën përfundimtare Kafka; pas kësaj, 3) konsumatorët marrin gjendjen e re.
Hej, dhe kjo magazinë e integruar e çelësave dhe vlerave është vërtet shumë e dobishme!
Siç u përmend më sipër, topologjia jonë me gjendje të ndarë përmban një magazinë çelësash dhe vlerash. Ne gjetëm disa mënyra për ta përdorur atë, dhe dy prej tyre janë përshkruar më poshtë.
Mënyra #1: përdorimi i magazinës së çelësave dhe vlerave gjatë llogaritjeve.
Depozita jonë e parë e çelësave dhe vlerave përmbante të dhëna ndihmëse që na duhej për llogaritjet. Për shembull, në disa raste, gjendja e ndarë u përcaktua sipas principit të "shumicës së votave". Në depo mund të mbaheshin të gjitha raportet më të fundit tëagjentëve në lidhje me një objekt të caktuar. Më pas, duke marrë një raport të ri nga ndonjë agent, ne mund të ruanim atë, të nxirrnim nga depo raportet e gjithë agjentëve të tjerë për gjendjen e të njëjtit objekt dhe të përsërisnim llogaritjen.
Më poshtë në ilustrimin 4 tregohet se si ne hapëm aksesin në depozitat e çelësave dhe vlerave për metodën e përpunimit të procesorit, kështu që më pas mund të përpunonim një mesazh të ri.

Ilustrimi 4: hapja e aksesit në depozitat e çelësave dhe vlerave për metodën e përpunimit të procesorit (pas kësaj, në çdo skenar që punon me gjendjen e ndarë, nevojitet të implementohet metoda doProcess)
Opcioni #2: krijimi i një API CRUD mbi Kafka Streams
Pas pasi për të ndërtuar fluxin tonë bazë të detyrave, filluam të provonim të shkruanim një RESTful CRUD API për mikroshërbimet tona me gjendje të ndarë. Ne donim që të mund të nxirrnim gjendjen e disa ose të gjitha objekteve, si dhe të vendosnim ose hiqnim gjendjen e një objekti (kjo është e dobishme për mbështetje në anën serverike).
Për të mbështetur të gjithë API-në Get State, sa herë na nevojitej të llogarisnim përsëri gjendjen gjatë përpunimit, ne e ruanim atë për një kohë të gjatë në ruajtjen e integruar të çelësave dhe vlerave. Në këtë rast, është mjaft e thjeshtë të implementoni një API të tillë duke përdorur një instancë të vetme të Kafka Streams, siç është treguar në listimin më poshtë:

Ilustrimi 5: përdorimi i ruajtjes së integruar të çelësave dhe vlerave për të marrë gjendjen e parakalkuluar të objektit
Përditësimi i gjendjes së objektit përmes API-së gjithashtu nuk është e vështirë për t'u realizuar. Në parim, për këtë vetëm duhet të krijoni një prodhues Kafka, dhe me të të bëni një shkronjë, në të cilën përmban gjendjen e re. Kështu garanton që të gjitha mesazhet e gjeneruara përmes API-së do të përpunohen në të njëjtën mënyrë si ato që vijnë nga prodhues të tjerë (p.sh. agjentët).

Ilustrimi 6: mund të përcaktojmë gjendjen e objektit përmes produesit Kafka
Një komplikim i vogël: Kafka ka shumë parti
Më pas donim të shpërndanim ngarkesën e përpunimit dhe të përmirësonim disponueshmërinë, duke ofruar për çdo skenar një klaster mikroshërbimesh me gjendje të përbashkët. Konfigurimi doli të ishte mjaft i thjeshtë: pasi konfiguruam të gjithë instancat që të punonin me të njëjtin ID të aplikacionit (dhe me të njëjtat serverë të ngarkesës fillestare), pothuajse gjithçka tjetër u realizua automatikisht. Ne gjithashtu caktuam që çdo temë burimi do të përbëhej nga disa parti, në mënyrë që secilës instancë t'i jepet një nëngrup i tillë partitesh.
Gjithashtu do të përmend se këtu është zakon që të bëhet një kopje rezervë e magazinës së gjendjeve, që, për shembull, në rast rikuperimi pas një dështimi, ajo të transferohet në një instancë tjetër. Për çdo magazinë gjendjesh në Kafka Streams krijohet një temë e riprodhueshme me një regjistër ndryshimesh (ku ndiqen azhurnimet lokale). Kështu, Kafka vazhdimisht mbulon magazinën e gjendjeve. Prandaj, në rast dështimi të ndonjë instancë të Kafka Streams, magazina e gjendjeve mund të rikuperohet shpejt në një instancë tjetër, ku do të transferohen partitë përkatëse. Testet tona treguan se kjo bëhet për pak sekonda, edhe nëse në magazinë ka miliona regjistrime.
Duke kaluar nga një mikroshërbim me një gjendje të ndarë në një klaster mikroshërbimesh, realizimi i Get State API nuk është kaq triviale. Në situatën e re, në ruajtjen e gjendjeve të çdo mikroshërbimi ndodhet vetëm një pjesë e tablosë përkatëse (ato objekte të cilat çelësat e tyre u shfaqën në një parti të caktuar). Duhej të përcaktonim se në cilin instancë ndodhej gjendja e objektit që na nevojitej, dhe këtë e bënim në bazë të metadata e rrjedhjeve, siç tregohet më poshtë:

Ilustrimi 7: me ndihmën e metadata e rrjedhave ne përcaktojmë nga cilë instancë të kërkojmë gjendjen e objektit të kërkuar; një qasje e tillë u përdor për GET ALL API
Konkluzionet kryesore
Ruajtjet e gjendjeve në Kafka Streams de facto mund të shërbejnë si një bazë të dhënash të shpërndarë,
- e cila riplikohet vazhdimisht në Kafka
- Për një sistem të tillë, është e lehtë të ndërtohet një CRUD API
- Përpunimi i shumë partive është pak më kompleks
- Gjithashtu është e mundur të shtoni një ose më shumë ruajtje gjendjesh në topologjinë e rrjedhës për të ruajtur të dhëna ndihmëse. Ky variant mund të përdoret për:
- Ruajtjen afatgjatë të të dhënave, të nevojshme për llogaritjet gjatë përpunimit të rrjedhave
- Depërtimi i të dhënave me afat të gjatë, të cilat mund të jenë të dobishme gjatë inicializimit të ardhshëm të instancës së transmetimit
- pjesĂ« tĂ« tjeraâŠ
Falë këtyre dhe avantazheve të tjera, Kafka Streams është një zgjidhje e shkëlqyer për mbështetje globale të gjendjes në një sistem të tillë të shpërndarë si i yni. Kafka Streams ka treguar besueshmëri të madhe në prodhim (që nga vendosja e saj, ne praktikisht nuk kemi humbur mesazhe), dhe jemi të sigurt se kapacitetet e saj nuk përfundojnë këtu!
Burimi: habr.com
