Hei Habr!
Vă reamintim că în urma cărții despre am publicat o lucrare la fel de interesantă despre bibliotecă .

Deocamdată, comunitatea tocmai învață limitele acestui instrument puternic. Așadar, recent a fost publicat un articol, a cărui traducere dorim să vă prezentăm. Din propria experiență, autorul spune cum să transforme Kafka Streams într-un stoc de date distribuit. Bucură-te de lectură!
biblioteca Apache utilizat în întreaga lume în întreprinderi pentru procesarea fluxului distribuit pe lângă Apache Kafka. Unul dintre aspectele subapreciate ale acestui cadru este că vă permite să stocați starea locală produsă pe baza procesării firelor.
În acest articol, vă voi spune cum a reușit compania noastră să folosească profitabil această oportunitate atunci când a dezvoltat un produs pentru securitatea aplicațiilor în cloud. Folosind Kafka Streams, am creat microservicii de stat partajate, fiecare dintre acestea fiind o sursă de informații fiabile cu toleranță la erori și foarte disponibilă despre starea obiectelor din sistem. Pentru noi, acesta este un pas înainte atât în ceea ce privește fiabilitatea, cât și ușurința suportului.
Dacă sunteți interesat de o abordare alternativă care vă permite să utilizați o singură bază de date centrală pentru a susține starea formală a obiectelor dvs., citiți-o, va fi interesant...
De ce am crezut că este timpul să schimbăm modul în care lucrăm cu starea comună
Aveam nevoie să menținem starea diferitelor obiecte pe baza rapoartelor agenților (de exemplu: site-ul a fost atacat)? Înainte de a migra la Kafka Streams, ne-am bazat adesea pe o singură bază de date centrală (+ API de serviciu) pentru gestionarea statului. Această abordare are dezavantajele sale: menținerea coerenței și a sincronizării devine o adevărată provocare. Baza de date poate deveni un blocaj sau poate ajunge în și suferă de imprevizibilitate.

Figura 1: Un scenariu tipic cu stări divizate văzut înainte de tranziția la
Kafka și Kafka Streams: agenții își comunică opiniile prin API, starea actualizată este calculată printr-o bază de date centrală
Faceți cunoștință cu Kafka Streams, facilitând crearea de microservicii de stat partajate
În urmă cu aproximativ un an, am decis să aruncăm o privire atentă asupra scenariilor noastre comune pentru a aborda aceste probleme. Am decis imediat să încercăm Kafka Streams - știm cât de scalabil, foarte disponibil și tolerant la erori este și cât de bogată este funcționalitatea sa de streaming (transformări, inclusiv cele cu stare). Exact ce aveam nevoie, ca să nu mai vorbim de cât de matur și de fiabil a devenit sistemul de mesagerie în Kafka.
Fiecare dintre microservicii cu stat pe care le-am creat a fost construit pe o instanță Kafka Streams cu o topologie destul de simplă. Acesta a constat din 1) o sursă 2) un procesor cu un depozit persistent de cheie-valoare 3) un receptor:

Figura 2: Topologia implicită a instanțelor noastre de streaming pentru microservicii cu stare. Rețineți că aici există și un depozit care conține metadate de planificare.
În această nouă abordare, agenții compun mesaje care sunt introduse în subiectul sursă, iar consumatorii, de exemplu, un serviciu de notificare prin e-mail, primesc starea partajată calculată prin receptor (subiect de ieșire).

Figura 3: Nou exemplu de flux de sarcini pentru un scenariu cu microservicii partajate: 1) agentul generează un mesaj care ajunge la subiectul sursă Kafka; 2) un microserviciu cu stare partajată (folosind Kafka Streams) îl procesează și scrie starea calculată în subiectul Kafka final; după care 3) consumatorii acceptă noul stat
Hei, acest magazin cheie-valoare încorporat este de fapt foarte util!
După cum sa menționat mai sus, topologia noastră de stare partajată conține un magazin cheie-valoare. Am găsit mai multe opțiuni de utilizare, iar două dintre ele sunt descrise mai jos.
Opțiunea #1: utilizați un magazin cheie-valoare pentru calcule
Primul nostru magazin cheie-valoare conținea datele auxiliare de care aveam nevoie pentru calcule. De exemplu, în unele cazuri, statul comun a fost determinat de principiul „voturilor majorității”. Depozitul ar putea deține toate cele mai recente rapoarte ale agenților privind starea unui obiect. Apoi, când am primit un nou raport de la un agent sau altul, am putea să-l salvăm, să preluăm rapoarte de la toți ceilalți agenți despre starea aceluiași obiect din stocare și să repetam calculul.
Figura 4 de mai jos arată cum am expus stocul cheie/valoare la metoda de procesare a procesorului, astfel încât noul mesaj să poată fi apoi procesat.

Ilustrația 4: deschidem accesul la magazinul cheie-valoare pentru metoda de procesare a procesorului (după aceasta, fiecare script care funcționează cu stare partajată trebuie să implementeze metoda doProcess)
Opțiunea #2: Crearea unui API CRUD pe lângă Kafka Streams
După ce ne-am stabilit fluxul de sarcini de bază, am început să încercăm să scriem un API CRUD RESTful pentru microserviciile noastre de stat partajate. Am vrut să putem regăsi starea unora sau a tuturor obiectelor, precum și să setăm sau să eliminăm starea unui obiect (utilă pentru suportul backend).
Pentru a susține toate API-urile Get State, ori de câte ori am avut nevoie să recalculăm starea în timpul procesării, am stocat-o mult timp într-un magazin cheie-valoare încorporat. În acest caz, devine destul de simplu să implementați un astfel de API folosind o singură instanță de Kafka Streams, așa cum se arată în lista de mai jos:

Figura 5: Utilizarea stocului de cheie-valoare încorporat pentru a obține starea precalculată a unui obiect
Actualizarea stării unui obiect prin intermediul API-ului este, de asemenea, ușor de implementat. Practic, tot ce trebuie să faci este să creezi un producător Kafka și să-l folosești pentru a realiza o înregistrare care conține noua stare. Acest lucru asigură că toate mesajele generate prin API vor fi procesate în același mod ca și cele primite de la alți producători (de ex. agenți).

Figura 6: Puteți seta starea unui obiect folosind producătorul Kafka
Mică complicație: Kafka are multe partiții
În continuare, am dorit să distribuim sarcina de procesare și să îmbunătățim disponibilitatea prin furnizarea unui cluster de microservicii în stare partajată per scenariu. Configurarea a fost ușoară: odată ce am configurat toate instanțele să ruleze sub același ID de aplicație (și aceleași servere de bootstrap), aproape totul s-a făcut automat. De asemenea, am specificat că fiecare subiect sursă ar fi format din mai multe partiții, astfel încât fiecărei instanțe să i se poată atribui un subset de astfel de partiții.
De asemenea, voi menționa că este o practică obișnuită să faceți o copie de rezervă a magazinului de stat, astfel încât, de exemplu, în caz de recuperare după un eșec, să transferați această copie într-o altă instanță. Pentru fiecare magazin de stat din Kafka Streams, este creat un subiect replicat cu un jurnal de modificări (care urmărește actualizările locale). Astfel, Kafka susține constant magazinul de stat. Prin urmare, în cazul unei eșecuri a uneia sau altei instanțe Kafka Streams, stocul de stare poate fi restaurat rapid pe o altă instanță, unde vor merge partițiile corespunzătoare. Testele noastre au arătat că acest lucru se face în câteva secunde, chiar dacă în magazin există milioane de înregistrări.
Trecând de la un singur microserviciu cu stare partajată la un cluster de microservicii, implementarea API-ului Get State devine mai puțin trivială. În noua situație, magazinul de stare al fiecărui microserviciu conține doar o parte din imaginea de ansamblu (acele obiecte ale căror chei au fost mapate la o anumită partiție). A trebuit să stabilim care instanță conținea starea obiectului de care aveam nevoie și am făcut acest lucru pe baza metadatelor firului, după cum se arată mai jos:

Figura 7: Folosind metadatele fluxului, determinăm din ce instanță să interogăm starea obiectului dorit; o abordare similară a fost utilizată cu API-ul GET ALL
Principalele constatări
Magazinele de stat din Kafka Streams pot servi ca o bază de date distribuită de facto,
- replicat constant în Kafka
- Un API CRUD poate fi construit cu ușurință pe deasupra unui astfel de sistem
- Gestionarea mai multor partiții este puțin mai complicată
- De asemenea, este posibil să adăugați unul sau mai multe depozite de stare la topologia de streaming pentru a stoca date auxiliare. Această opțiune poate fi utilizată pentru:
- Stocarea pe termen lung a datelor necesare pentru calcule în timpul procesării fluxului
- Stocarea pe termen lung a datelor care poate fi utilă data viitoare când instanța de streaming este furnizată
- mult mai mult...
Acestea și alte avantaje fac ca Kafka Streams să fie potrivit pentru menținerea stării globale într-un sistem distribuit ca al nostru. Kafka Streams s-a dovedit a fi foarte fiabil în producție (practic nu am avut nicio pierdere de mesaje de când l-am implementat) și suntem încrezători că capabilitățile sale nu se vor opri aici!
Sursa: www.habr.com
