{"id":35786,"date":"2019-10-31T22:06:19","date_gmt":"2019-10-31T19:06:19","guid":{"rendered":"https:\/\/prohoster.info\/blog\/kniga-kafka-streams-v-dejstvii-prilozheniya-i-mikroservisy-dlya-raboty-v-realnom-vremeni\/"},"modified":"2019-10-31T22:06:19","modified_gmt":"2019-10-31T19:06:19","slug":"kniga-kafka-streams-v-dejstvii-prilozheniya-i-mikroservisy-dlya-raboty-v-realnom-vremeni","status":"publish","type":"post","link":"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/kniga-kafka-streams-v-dejstvii-prilozheniya-i-mikroservisy-dlya-raboty-v-realnom-vremeni","title":{"rendered":"Cartea \u201eKafka Streams \u00een ac\u021biune. Aplica\u021bii \u0219i microservicii pentru lucru \u00een timp real\u201d","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/piter\/blog\/457756\/\"><img decoding=\"async\" alt=\"Cartea \u201eKafka Streams \u00een ac\u021biune. Aplica\u021bii \u0219i microservicii pentru lucru \u00een timp real\u201d\" src=\"\/wp-content\/uploads\/6f8bd2b31b87b0c760c1148515893c43.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex> Salut, Habr\u0103ri! Aceast\u0103 carte este potrivit\u0103 pentru orice dezvoltator care dore\u0219te s\u0103 \u00een\u021beleag\u0103 procesarea \u00een flux. \u00cen\u021belegerea program\u0103rii distribuite va ajuta la studierea mai bun\u0103 a Kafka \u0219i Kafka Streams. Ar fi bine s\u0103 cuno\u0219ti \u0219i cadrul Kafka, dar nu este obligatoriu: \u00ee\u021bi voi explica tot ce trebuie s\u0103 \u0219tii. Dezvoltatorii experimenta\u021bi de Kafka, la fel ca \u0219i \u00eencep\u0103torii, vor \u00eenv\u0103\u021ba din aceast\u0103 carte cum s\u0103 creeze aplica\u021bii interesante pentru procesarea \u00een flux folosind biblioteca Kafka Streams. Dezvoltatorii Java de nivel mediu \u0219i \u00eenalt, deja familiariza\u021bi cu concepte precum serializarea, vor \u00eenv\u0103\u021ba s\u0103 \u00ee\u0219i aplice abilit\u0103\u021bile pentru a crea aplica\u021bii Kafka Streams. Codul surs\u0103 al c\u0103r\u021bii este scris \u00een Java 8 \u0219i folose\u0219te semnificativ sintaxa expresiilor lambda din Java 8, astfel c\u0103 abilitatea de a lucra cu func\u021bii lambda (chiar \u0219i \u00een alte limbaje de programare) \u00ee\u021bi va fi de folos.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h3>Fragment. 5.3. Agregarea \u0219i opera\u021biile pe fereastr\u0103<\/h3>\n<p>\n\u00cen aceast\u0103 sec\u021biune, vom trece la studierea celor mai promi\u021b\u0103toare p\u0103r\u021bi ale Kafka Streams. P\u00e2n\u0103 acum, am analizat urm\u0103toarele aspecte ale Kafka Streams:<\/p>\n<ul>\n<li>crearea unei topologii de procesare;<\/li>\n<li>utilizarea st\u0103rii \u00een aplica\u021biile de flux;<\/li>\n<li>efectuarea de conexiuni \u00eentre fluxurile de date;<\/li>\n<li>diferen\u021bele \u00eentre fluxurile de evenimente (KStream) \u0219i fluxurile de actualiz\u0103ri (KTable).<\/li>\n<\/ul>\n<p>\n\u00cen exemplele urm\u0103toare, vom aduna toate aceste elemente \u00eempreun\u0103. De asemenea, te vei familiariza cu opera\u021biile pe feron\u021b\u0103 \u2014 o alt\u0103 posibilitate extraordinar\u0103 a aplica\u021biilor de flux. Primul nostru exemplu va fi o agregare simpl\u0103.<\/p>\n<h3>5.3.1. Agregarea volumului v\u00e2nz\u0103rilor de ac\u021biuni pe industrii<\/h3>\n<p>\nAgregarea \u0219i gruparea sunt instrumente esen\u021biale \u00een lucrul cu datele de flux. Studierea \u00eenregistr\u0103rilor individuale pe m\u0103sur\u0103 ce acestea sosesc se dovede\u0219te adesea insuficient\u0103. Pentru a extrage informa\u021bii suplimentare din date, sunt necesare gruparea \u0219i combinarea acestora.<\/p>\n<p>\u00cen acest exemplu, va trebui s\u0103 \u00eembraci costumul unui trader intradag care trebuie s\u0103 urm\u0103reasc\u0103 volumul v\u00e2nz\u0103rilor de ac\u021biuni ale companiilor din mai multe industrii. \u00cen special, te intereseaz\u0103 cinci companii cu cele mai mari volume de v\u00e2nz\u0103ri de ac\u021biuni \u00een fiecare dintre industriile respective.<\/p>\n<p>Pentru o astfel de agregare, vor fi necesari c\u00e2\u021biva pa\u0219i pentru a traduce datele \u00een forma dorit\u0103 (dac\u0103 vorbim \u00een termeni generali).<\/p>\n<ol>\n<li>Creeaz\u0103 o surs\u0103 bazat\u0103 pe un topic pentru a publica informa\u021bii brute despre tranzac\u021biile cu ac\u021biuni. Va trebui s\u0103 map\u0103m un obiect de tip StockTransaction \u00eentr-un obiect de tip ShareVolume. Problema este c\u0103 obiectul StockTransaction con\u021bine metadate despre v\u00e2nz\u0103ri, iar noi avem nevoie doar de datele despre num\u0103rul de ac\u021biuni v\u00e2ndute.<\/li>\n<li>Grupeaz\u0103 datele ShareVolume dup\u0103 simbolurile ac\u021biunilor. Dup\u0103 grupare, aceste date pot fi consolidate \u00een sume intermediare ale volumului de v\u00e2nz\u0103ri ale ac\u021biunilor. Este de remarcat c\u0103 metoda KStream.groupBy returneaz\u0103 o instan\u021b\u0103 de tip KGroupedStream. O instan\u021b\u0103 de KTable poate fi ob\u021binut\u0103 apel\u00e2nd apoi metoda KGroupedStream.reduce.<\/li>\n<\/ol>\n<p><\/p>\n<blockquote><p><b>Ce este interfa\u021ba KGroupedStream?<\/b><\/p>\n<p>Metodele KStream.groupBy \u0219i KStream.groupByKey returneaz\u0103 o instan\u021b\u0103 de KGroupedStream. KGroupedStream reprezint\u0103 o viziune intermediar\u0103 a fluxului de evenimente dup\u0103 gruparea pe chei. Nu este destinat pentru a fi utilizat direct. \u00cen schimb, KGroupedStream este folosit pentru opera\u021biuni de agregare, al c\u0103ror rezultat este \u00eentotdeauna un KTable. \u0218i deoarece rezultatul opera\u021biunilor de agregare este un KTable \u0219i se aplic\u0103 un depozit de st\u0103ri, este posibil ca nu toate actualiz\u0103rile rezultate s\u0103 fie trimise mai departe \u00een canal.<\/p>\n<p>Metoda KTable.groupBy returneaz\u0103 un KGroupedTable analogic \u2014 o reprezentare intermediar\u0103 a fluxului de actualiz\u0103ri, regroupate pe cheie.<\/p><\/blockquote>\n<p>\nS\u0103 facem o mic\u0103 pauz\u0103 \u0219i s\u0103 ne uit\u0103m la fig. 5.9, care arat\u0103 ce am realizat. Aceast\u0103 topologie ar trebui s\u0103 v\u0103 fie deja bine cunoscut\u0103.<\/p>\n<p><img decoding=\"async\" alt=\"Cartea \u201eKafka Streams \u00een ac\u021biune. Aplica\u021bii \u0219i microservicii pentru lucru \u00een timp real\u201d\" src=\"\/wp-content\/uploads\/9fd61317cde376362adcaeec72908919.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nS\u0103 ne uit\u0103m acum la codul pentru aceast\u0103 topologie (poate fi g\u0103sit \u00een fi\u0219ierul src\/main\/java\/bbejeck\/chapter_5\/AggregationsAndReducingExample.java) (listing 5.2).<\/p>\n<p><img decoding=\"async\" alt=\"Cartea \u201eKafka Streams \u00een ac\u021biune. Aplica\u021bii \u0219i microservicii pentru lucru \u00een timp real\u201d\" src=\"\/wp-content\/uploads\/f937287e448295fbd467c283ceca316a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nCodul prezentat este concis \u0219i realizeaz\u0103 multe ac\u021biuni \u00eentr-un num\u0103r mic de linii. \u00cen primul parametru al metodei builder.stream, pute\u021bi observa ceva nou: valoarea tipului enumerat AutoOffsetReset.EARLIEST (exist\u0103 de asemenea \u0219i LATEST), definit\u0103 folosind metoda Consumed.withOffsetResetPolicy. Prin intermediul acestui tip enumerat, se poate specifica strategia de resetare a deplas\u0103rii pentru fiecare KStream sau KTable, av\u00e2nd prioritate asupra parametrului de resetare a deplas\u0103rii din configura\u021bie.<\/p>\n<blockquote><p><b>GroupByKey \u0219i GroupBy<\/b><\/p>\n<p>\u00cen interfa\u021ba KStream exist\u0103 dou\u0103 metode pentru gruparea \u00eenregistr\u0103rilor: GroupByKey \u0219i GroupBy. Ambele returneaz\u0103 un KGroupedTable, astfel \u00eenc\u00e2t o \u00eentrebare firesc\u0103 poate ap\u0103rea: care este diferen\u021ba dintre ele \u0219i c\u00e2nd s\u0103 folosi\u021bi fiecare dintre ele?<\/p>\n<p>Metoda GroupByKey se aplic\u0103 atunci c\u00e2nd cheile din KStream sunt deja nenule. De asemenea, indicatorul \u201enecesit\u0103 reproiectare\u201d nu a fost niciodat\u0103 setat.<\/p>\n<p>Metoda GroupBy presupune c\u0103 a\u021bi schimbat cheile pentru grupare, astfel c\u0103 indicatorul de reproiectare este setat pe true. Execu\u021bia dup\u0103 metoda GroupBy a conexiunilor, agreg\u0103rilor etc. va duce la reproiectarea automat\u0103.<br \/>\nRezumat: ar trebui s\u0103 utiliza\u021bi GroupByKey c\u00e2nd este posibil, \u0219i nu GroupBy.<\/p><\/blockquote>\n<p>\nCe fac metodele mapValues \u0219i groupBy este clar, a\u0219a c\u0103 s\u0103 arunc\u0103m o privire asupra metodei sum() (o pute\u021bi g\u0103si \u00een fi\u0219ierul src\/main\/java\/bbejeck\/model\/ShareVolume.java) (listare 5.3).<\/p>\n<p><img decoding=\"async\" alt=\"Cartea \u201eKafka Streams \u00een ac\u021biune. Aplica\u021bii \u0219i microservicii pentru lucru \u00een timp real\u201d\" src=\"\/wp-content\/uploads\/8e9a6f873594f9b5fef9a96c42353a61.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMetoda ShareVolume.sum returneaz\u0103 suma intermediar\u0103 a volumului v\u00e2nz\u0103rilor de ac\u021biuni, iar rezultatul \u00eentregului lan\u021b de calcul este un obiect KTable. Acum \u00een\u021belege\u021bi rolul pe care \u00eel joac\u0103 KTable. Atunci c\u00e2nd obiectele ShareVolume sunt primite, \u00een obiectul KTable corespunz\u0103tor se p\u0103streaz\u0103 ultima actualizare valid\u0103. Este important s\u0103 nu uit\u0103m c\u0103 toate actualiz\u0103rile sunt reflectate \u00een shareVolumeKTable precedent, dar nu toate sunt trimise mai departe.<\/p>\n<p>Apoi, folosind acest KTable, execut\u0103m agregarea (pe baza num\u0103rului de ac\u021biuni v\u00e2ndute), pentru a ob\u021bine cinci companii cu cele mai mari volume de v\u00e2nz\u0103ri de ac\u021biuni din fiecare ramur\u0103 industrial\u0103. Ac\u021biunile noastre vor fi similare cu cele din prima agregare.<\/p>\n<ol>\n<li>Executa\u021bi o alt\u0103 opera\u021bie groupBy pentru a grupa obiectele ShareVolume individuale dup\u0103 sectoarele industriale.<\/li>\n<li>Trebuie s\u0103 \u00eencepem s\u0103 sum\u0103m obiectele ShareVolume. De data aceasta, obiectul de agregare este o coad\u0103 de prioritate de dimensiune fix\u0103. \u00centr-o astfel de coad\u0103 de dimensiune fix\u0103, se p\u0103streaz\u0103 doar cinci companii cu cele mai mari cantit\u0103\u021bi de ac\u021biuni v\u00e2ndute.<\/li>\n<li>Maparea cozii din punctul anterior \u00eentr-o valoare de tip \u0219ir \u0219i returnarea celor cinci ac\u021biuni cele mai v\u00e2ndute dup\u0103 num\u0103rul de ac\u021biuni pe sectoare industriale.<\/li>\n<li>Scrie\u021bi rezultatele sub form\u0103 de \u0219ir \u00een topic.<\/li>\n<\/ol>\n<p>\n\u00cen figura 5.10 este ilustrat graficul topologiei fluxului de date. Dup\u0103 cum pute\u021bi observa, al doilea ciclu de procesare este destul de simplu.<\/p>\n<p><img decoding=\"async\" alt=\"Cartea \u201eKafka Streams \u00een ac\u021biune. Aplica\u021bii \u0219i microservicii pentru lucru \u00een timp real\u201d\" src=\"\/wp-content\/uploads\/dabd1507eee267038edb7f8d76d8d8ae.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nAcum, av\u00e2nd clar \u00een minte structura acestui al doilea ciclu de procesare, putem consulta codul s\u0103u surs\u0103 (\u00eel ve\u021bi g\u0103si \u00een fi\u0219ierul src\/main\/java\/bbejeck\/chapter_5\/AggregationsAndReducingExample.java) (listare 5.4).<\/p>\n<p>\u00cen acest ini\u021bializator exist\u0103 o variabil\u0103 fixedQueue. Acesta este un obiect personalizat - un adaptor pentru java.util.TreeSet, care este utilizat pentru a urm\u0103ri cele N cele mai mari rezultate \u00een ordine descresc\u0103toare a num\u0103rului de ac\u021biuni v\u00e2ndute.<\/p>\n<p><img decoding=\"async\" alt=\"Cartea \u201eKafka Streams \u00een ac\u021biune. Aplica\u021bii \u0219i microservicii pentru lucru \u00een timp real\u201d\" src=\"\/wp-content\/uploads\/488b072b0d91b81c925ca72291e69e48.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nTe-ai \u00eent\u00e2lnit deja cu apelurile groupBy \u0219i mapValues, a\u0219a c\u0103 nu ne vom opri asupra lor (apel\u0103m metoda KTable.toStream, deoarece metoda KTable.print este considerat\u0103 \u00eenvechit\u0103). Dar tu nu ai v\u0103zut \u00eenc\u0103 versiunea KTable a metodei aggregate(), astfel c\u0103 vom petrece pu\u021bin timp discut\u00e2nd despre aceasta.<\/p>\n<p>A\u0219a cum \u00ee\u021bi aminte\u0219ti, KTable se distinge prin faptul c\u0103 \u00eenregistr\u0103rile cu acelea\u0219i chei sunt considerate actualiz\u0103ri. KTable \u00eenlocuie\u0219te vechea \u00eenregistrare cu una nou\u0103. Agregarea se face \u00een mod similar: se agreg\u0103 ultimele \u00eenregistr\u0103ri cu aceea\u0219i cheie. Atunci c\u00e2nd o \u00eenregistrare sose\u0219te, aceasta este ad\u0103ugat\u0103 \u00een instan\u021ba clasei FixedSizePriorityQueue cu ajutorul sumatorului (al doilea parametru \u00een apelul metodei aggregate), dar dac\u0103 exist\u0103 deja o alt\u0103 \u00eenregistrare cu acelea\u0219i cheie, atunci vechea \u00eenregistrare este eliminat\u0103 cu ajutorul sc\u0103z\u0103torului (al treilea parametru \u00een apelul metodei aggregate).<\/p>\n<p>Asta \u00eenseamn\u0103 c\u0103 agregatorul nostru, FixedSizePriorityQueue, nu agregheaz\u0103 toate valorile cu aceea\u0219i cheie, ci p\u0103streaz\u0103 suma mobile a cantit\u0103\u021bilor celor N cele mai v\u00e2ndute tipuri de ac\u021biuni. Fiecare \u00eenregistrare care soseste con\u021bine num\u0103rul total de ac\u021biuni v\u00e2ndute p\u00e2n\u0103 acum. KTable \u00ee\u021bi va oferi informa\u021bii despre ce ac\u021biuni ale companiilor sunt cele mai v\u00e2ndute \u00een prezent, agregarea mobil\u0103 a fiec\u0103rei actualiz\u0103ri nu este necesar\u0103.<\/p>\n<p>Am \u00eenv\u0103\u021bat s\u0103 facem dou\u0103 lucruri importante:<\/p>\n<ul>\n<li>s\u0103 grup\u0103m valorile \u00eentr-o KTable dup\u0103 cheia comun\u0103;<\/li>\n<li>s\u0103 efectu\u0103m asupra acestor valori grupate opera\u021bii utile, cum ar fi reducerea \u0219i agregarea.<\/li>\n<\/ul>\n<p>\nCapacitatea de a efectua aceste opera\u021bii este esen\u021bial\u0103 pentru a \u00een\u021belege sensul datelor care circul\u0103 prin aplica\u021bia Kafka Streams \u0219i pentru a descoperi ce informa\u021bii aduc acestea.<\/p>\n<p>Am combinat, de asemenea, unele dintre conceptele cheie discutate anterior \u00een aceast\u0103 carte. \u00cen capitolul 4 am vorbit despre importan\u021ba unui stat local rezistent la erori pentru o aplica\u021bie de streaming. Primul exemplu din acest capitol a demonstrat de ce este at\u00e2t de important statul local - ofer\u0103 posibilitatea de a urm\u0103ri informa\u021biile pe care le-ai v\u0103zut deja. Accesul local permite evitarea \u00eent\u00e2rzierilor de re\u021bea, f\u0103c\u00e2nd aplica\u021bia mai performant\u0103 \u0219i mai rezistent\u0103 la erori.<\/p>\n<p>Atunci c\u00e2nd efectuezi vreo opera\u021bie de agregare sau de reducere, trebuie s\u0103 specifici numele magazinului de stare. Opera\u021biile de reducere \u0219i agregare returneaz\u0103 o instan\u021b\u0103 KTable, iar KTable folose\u0219te magazinul de stare pentru a \u00eenlocui vechile rezultate cu cele noi. A\u0219a cum ai observat, nu toate actualiz\u0103rile sunt trimise mai departe \u00een pipeline, ceea ce este important, deoarece opera\u021biile de agregare sunt destinate ob\u021binerii de informa\u021bii finale. Dac\u0103 nu se utilizeaz\u0103 statul local, KTable va trimite mai departe toate rezultatele agreg\u0103rii \u0219i reducerii.<\/p>\n<p>\u00cen continuare, vom analiza executarea unor opera\u021bii precum agregarea, \u00een cadrul unei anumite intervale de timp - a\u0219a-numitele opera\u021bii de fereastr\u0103 (windowing operations).<\/p>\n<h3>5.3.2. Opera\u021bii de fereastr\u0103<\/h3>\n<p>\n\u00cen sec\u021biunea anterioar\u0103, ne-am familiarizat cu agregarea \u0219i reducerea \u201emobil\u0103\u201d. Aplica\u021bia efectua o reducere continu\u0103 a volumului de v\u00e2nz\u0103ri de ac\u021biuni, urmat\u0103 de agregarea celor mai v\u00e2ndute cinci ac\u021biuni pe burs\u0103.<\/p>\n<p>Uneori, astfel de agreg\u0103ri \u0219i reduceri continue sunt necesare. Iar alteori, trebuie s\u0103 efectuezi opera\u021bii doar pe un anumit interval de timp. De exemplu, s\u0103 calculezi c\u00e2te tranzac\u021bii bursiere cu ac\u021biunile unei companii specifice au avut loc \u00een ultimele 10 minute. Sau c\u00e2\u021bi utilizatori au dat clic pe un nou banner publicitar \u00een ultimele 15 minute. Aplica\u021bia poate efectua astfel de opera\u021bii de mai multe ori, dar cu rezultate referitoare doar la intervalele de timp specificate (feron\u021be de timp).<\/p>\n<h3>Num\u0103rarea tranzac\u021biilor bursiere pe client<\/h3>\n<p>\n\u00cen exemplul urm\u0103tor, ne vom ocupa de urm\u0103rirea tranzac\u021biilor bursiere pentru mai mul\u021bi traderi - fie organiza\u021bii mari, fie investitori individuali ingenio\u0219i.<\/p>\n<p>Exist\u0103 dou\u0103 posibile motive pentru un astfel de tip de urm\u0103rire. Unul dintre ele este necesitatea de a \u0219ti ce cump\u0103r\u0103\/v\u00e2nd liderii din pia\u021b\u0103. Dac\u0103 ace\u0219ti juc\u0103tori mari \u0219i investitorii experimenta\u021bi observ\u0103 oportunit\u0103\u021bi, are sens s\u0103 urm\u0103m strategiile lor. Al doilea motiv este dorin\u021ba de a identifica eventualele semne de tranzac\u021bii ilegale care utilizeaz\u0103 informa\u021bii interne. Pentru aceasta, va trebui s\u0103 analiza\u021bi coresponden\u021ba dintre mari cre\u0219teri ale v\u00e2nz\u0103rilor \u0219i comunicatele de pres\u0103 importante.<\/p>\n<p>Aceast\u0103 urm\u0103rire const\u0103 din etape precum:<\/p>\n<ul>\n<li>crearea unui flux de citire din topicul stock-transactions;<\/li>\n<li>gruparea \u00eenregistr\u0103rilor de intrare dup\u0103 identificatorul cump\u0103r\u0103torului \u0219i simbolul bursier al ac\u021biunii. Apelul metodei groupBy returneaz\u0103 o instan\u021b\u0103 a clasei KGroupedStream;<\/li>\n<li>returnarea fluxului de date limitat de o fereastr\u0103 temporal\u0103 prin metoda KGroupedStream.windowedBy, ceea ce permite realizarea agreg\u0103rii pe feron\u021be. \u00cen func\u021bie de tipul de fereastr\u0103, este returnat fie TimeWindowedKStream, fie SessionWindowedKStream;<\/li>\n<li>contorizarea tranzac\u021biilor pentru opera\u021biunea de agregare. Fluxul de date pe feron\u021be determin\u0103 dac\u0103 o anumit\u0103 \u00eenregistrare este luat\u0103 \u00een calcul la aceast\u0103 contorizare;<\/li>\n<li>\u00eenregistrarea rezultatelor \u00een topic sau afi\u0219area lor \u00een consola de dezvoltare.<\/li>\n<\/ul>\n<p>\nTopologia acestei aplica\u021bii este simpl\u0103, dar o diagram\u0103 vizual\u0103 nu ar strica. S\u0103 ne uit\u0103m la figura 5.11.<\/p>\n<p>\u00cen continuare, vom explora func\u021bionalitatea opera\u021biunilor pe feron\u021be \u0219i codul corespunz\u0103tor.<\/p>\n<p><img decoding=\"async\" alt=\"Cartea \u201eKafka Streams \u00een ac\u021biune. Aplica\u021bii \u0219i microservicii pentru lucru \u00een timp real\u201d\" src=\"\/wp-content\/uploads\/67d9d8d8acb1370a7c7fe5cd9a8b6aa7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h3>Tipuri de feron\u021be<\/h3>\n<p>\n\u00cen Kafka Streams exist\u0103 trei tipuri de feron\u021be:<\/p>\n<ul>\n<li>de sesiuni;<\/li>\n<li>\u00abtumbling\u00bb (imediat);<\/li>\n<li>sliding\/\u00abhopping\u00bb (glisante\/\u00abs\u0103rind\u00bb).<\/li>\n<\/ul>\n<p>\nAlegerea unui tip depinde de cerin\u021bele de afaceri. Feron\u021bele \u00abtumbling\u00bb \u0219i \u00abhopping\u00bb sunt limitate \u00een timp, \u00een timp ce restric\u021biile feron\u021belor de sesiune sunt legate de ac\u021biunile utilizatorilor \u2014 durata sesiunii(-elor) este definit\u0103 exclusiv prin c\u00e2t de activ se comport\u0103 utilizatorul. Principalul aspect de re\u021binut este c\u0103 toate tipurile de feron\u021be se bazeaz\u0103 pe marcajele de dat\u0103\/ora ale \u00eenregistr\u0103rilor, nu pe timpul sistemului.<\/p>\n<p>\u00cen continuare, vom implementa topologia noastr\u0103 cu fiecare dintre tipurile de feron\u021be. Codul complet va fi prezentat doar \u00een primul exemplu; pentru celelalte tipuri de feron\u021be, nimic nu se va schimba, \u00een afar\u0103 de tipul opera\u021biei pe feron\u021be.<\/p>\n<h3>Feron\u021be de sesiune<\/h3>\n<p>\nFeronile de sesiune se deosebesc semnificativ de toate celelalte tipuri de feron. Ele sunt limitate nu at\u00e2t de timp, c\u00e2t de activitatea utilizatorului (sau activitatea entit\u0103\u021bii pe care dori\u021bi s\u0103 o urm\u0103ri\u021bi). Feronile de sesiune sunt delimitate prin intervale de inactivitate.<\/p>\n<p>Figura 5.12 ilustreaz\u0103 conceptul de feron de sesiune. O sesiune mai mic\u0103 se va contopi cu sesiunea din st\u00e2nga sa. Iar sesiunea din dreapta va fi separat\u0103, deoarece urmeaz\u0103 un interval lung de inactivitate. Feronile de sesiune se bazeaz\u0103 pe ac\u021biunile utilizatorilor, dar aplic\u0103 marcaje de dat\u0103\/ora din \u00eenregistr\u0103ri pentru a determina la ce sesiune apar\u021bine \u00eenregistrarea.<\/p>\n<p><img decoding=\"async\" alt=\"Cartea \u201eKafka Streams \u00een ac\u021biune. Aplica\u021bii \u0219i microservicii pentru lucru \u00een timp real\u201d\" src=\"\/wp-content\/uploads\/d39a5db7af7d6aa2194802622b2b47fd.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h3>Utilizarea feronilor de sesiune pentru a urm\u0103ri tranzac\u021biile de burs\u0103<\/h3>\n<p>\nVom folosi feronii de sesiune pentru a captura informa\u021bii despre tranzac\u021biile de burs\u0103. Implementarea feronilor de sesiune este prezentat\u0103 \u00een listarea 5.5 (care poate fi g\u0103sit\u0103 \u00een fi\u0219ierul src\/main\/java\/bbejeck\/chapter_5\/CountingWindowingAndKTableJoinExample.java).<\/p>\n<p><img decoding=\"async\" alt=\"Cartea \u201eKafka Streams \u00een ac\u021biune. Aplica\u021bii \u0219i microservicii pentru lucru \u00een timp real\u201d\" src=\"\/wp-content\/uploads\/2dcbd9a36baec0e746aad165121451b3.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nCele mai multe opera\u021biuni din aceast\u0103 topologie le-a\u021bi \u00eent\u00e2lnit deja, a\u0219a c\u0103 nu este nevoie s\u0103 le discut\u0103m din nou aici. \u00cens\u0103, exist\u0103 c\u00e2teva elemente noi pe care le vom discuta acum.<\/p>\n<p>La orice opera\u021biune groupBy se realizeaz\u0103 de obicei o opera\u021biune de agregare (agregare, compresie sau num\u0103rare). Pute\u021bi efectua fie o agregare cumulativ\u0103 cu totaluri progresive, fie o agregare pe feron, \u00een care se iau \u00een considerare \u00eenregistr\u0103rile dintr-un interval de timp specificat.<\/p>\n<p>Codul din listarea 5.5 efectueaz\u0103 num\u0103r\u0103toarea tranzac\u021biilor \u00een cadrul feronilor de sesiune. \u00cen figura 5.13, aceste ac\u021biuni sunt analizate pas cu pas.<\/p>\n<p>Prin apelul windowedBy(SessionWindows.with(twentySeconds).until(fifteenMinutes)), cre\u0103m un feron de sesiune cu un interval de inactivitate de 20 de secunde \u0219i un interval de p\u0103strare de 15 minute. Intervalul de inactivitate de 20 de secunde \u00eenseamn\u0103 c\u0103 aplica\u021bia va include orice \u00eenregistrare care ajunge \u00een intervalul de 20 de secunde de la finalizarea sau \u00eenceperea sesiunii curente \u00een sesiunea curent\u0103 (activ\u0103).<\/p>\n<p><img decoding=\"async\" alt=\"Cartea \u201eKafka Streams \u00een ac\u021biune. Aplica\u021bii \u0219i microservicii pentru lucru \u00een timp real\u201d\" src=\"\/wp-content\/uploads\/9bd47b04698086872fd135b4c67eb938.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n\u00cen continuare, specific\u0103m ce opera\u021biune de agregare trebuie efectuat\u0103 \u00een fereastra de sesiune \u2014 \u00een acest caz, count. Dac\u0103 \u00eenregistrarea de intrare dep\u0103\u0219e\u0219te intervalul de inactivitate (de orice parte de la marca de dat\u0103\/or\u0103), aplica\u021bia creeaz\u0103 o nou\u0103 sesiune. Intervalul de p\u0103strare \u00eenseamn\u0103 men\u021binerea sesiunii timp de un anumit timp \u0219i permite datele \u00eent\u00e2rziate care dep\u0103\u0219esc perioada de inactivitate a sesiunii, dar care \u00eenc\u0103 pot fi ata\u0219ate. \u00cen plus, \u00eenceputul \u0219i sf\u00e2r\u0219itul noii sesiuni, care rezult\u0103 din fuziune, corespund celei mai timpurii \u0219i celei mai recente m\u0103rci de dat\u0103\/or\u0103.<\/p>\n<p>S\u0103 lu\u0103m \u00een considerare c\u00e2teva \u00eenregistr\u0103ri din metoda count pentru a vedea cum func\u021bioneaz\u0103 sesiunile (tabelul 5.1).<\/p>\n<p><img decoding=\"async\" alt=\"Cartea \u201eKafka Streams \u00een ac\u021biune. Aplica\u021bii \u0219i microservicii pentru lucru \u00een timp real\u201d\" src=\"\/wp-content\/uploads\/ec04aae466d88c2d2349474069c8d541.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nLa primirea \u00eenregistr\u0103rilor, c\u0103ut\u0103m sesiuni deja existente cu aceea\u0219i cheie, cu timpul de sf\u00e2r\u0219it mai mic dec\u00e2t marca de dat\u0103\/or\u0103 curent\u0103 \u2014 intervalul de inactivitate \u0219i timpul de \u00eenceput mai mare dec\u00e2t marca de dat\u0103\/or\u0103 curent\u0103 + intervalul de inactivitate. Av\u00e2nd \u00een vedere acest lucru, cele patru \u00eenregistr\u0103ri din tabelul 5.1 se combin\u0103 \u00eentr-o singur\u0103 sesiune \u00een felul urm\u0103tor.<\/p>\n<p>1. Prima \u00eenregistrare primit\u0103 este \u00eenregistrarea 1, astfel c\u0103 timpul de \u00eenceput este egal cu timpul de sf\u00e2r\u0219it \u0219i este 00:00:00.<\/p>\n<p>2. Apoi vine \u00eenregistrarea 2, iar noi c\u0103ut\u0103m sesiuni care se termin\u0103 nu mai devreme de 23:59:55 \u0219i \u00eencep nu mai t\u00e2rziu de 00:00:35. G\u0103sim \u00eenregistrarea 1 \u0219i combin\u0103m sesiunile 1 \u0219i 2. Lu\u0103m timpul de \u00eenceput al sesiunii 1 (cel mai timpuriu) \u0219i timpul de sf\u00e2r\u0219it al sesiunii 2 (cel mai tardiv), astfel \u00eenc\u00e2t noua noastr\u0103 sesiune \u00eencepe la 00:00:00 \u0219i se termin\u0103 la 00:00:15.<\/p>\n<p>3. Vine \u00eenregistrarea 3, c\u0103ut\u0103m sesiuni \u00eentre 00:00:30 \u0219i 00:01:10 \u0219i nu g\u0103sim niciuna. Ad\u0103ug\u0103m a doua sesiune pentru cheia 123-345-654,FFBE, care \u00eencepe \u0219i se termin\u0103 la 00:00:50.<\/p>\n<p>4. Vine \u00eenregistrarea 4, iar noi c\u0103ut\u0103m sesiuni \u00eentre 23:59:45 \u0219i 00:00:25. De data aceasta se g\u0103sesc ambele sesiuni \u2014 1 \u0219i 2. Toate cele trei sesiuni se combin\u0103 \u00eentr-o singur\u0103 sesiune, cu timpul de \u00eenceput 00:00:00 \u0219i timpul de sf\u00e2r\u0219it 00:00:15.<\/p>\n<p>Din ceea ce este spus \u00een aceast\u0103 sec\u021biune, merit\u0103 re\u021binut urm\u0103toarele aspecte importante:<\/p>\n<ul>\n<li>sesiunile \u2014 nu sunt feronete de dimensiuni fixe. Durata unei sesiuni este determinat\u0103 de activitatea dintr-un interval de timp dat;<\/li>\n<li>m\u0103rcile de dat\u0103\/or\u0103 din date determin\u0103 dac\u0103 un eveniment se \u00eencadreaz\u0103 \u00eentr-o sesiune existent\u0103 sau \u00eentr-un interval de inactivitate.<\/li>\n<\/ul>\n<p>\n\u00cen continuare, vom discuta urm\u0103toarea variant\u0103 de feronete \u2014 feronetele \u201er\u0103sturnate\u201d.<\/p>\n<h3>Feronetele \u201er\u0103sturnate\u201d<\/h3>\n<p>\nFeron\u021bele \u201etumbling\u201d captureaz\u0103 evenimentele care au loc \u00eentr-un anumit interval de timp. Imagina\u021bi-v\u0103 c\u0103 trebuie s\u0103 captura\u021bi toate tranzac\u021biile bursiere ale unei companii la fiecare 20 de secunde, astfel c\u0103 aduna\u021bi toate evenimentele din acest interval. La sf\u00e2r\u0219itul intervalului de 20 de secunde, fereastra \u201etumbling\u201d se mut\u0103 pe un nou interval de observa\u021bie de 20 de secunde. Figura 5.14 ilustreaz\u0103 aceast\u0103 situa\u021bie.<\/p>\n<p><img decoding=\"async\" alt=\"Cartea \u201eKafka Streams \u00een ac\u021biune. Aplica\u021bii \u0219i microservicii pentru lucru \u00een timp real\u201d\" src=\"\/wp-content\/uploads\/e90e560d9ddda5e2e524b7c387ad9874.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDup\u0103 cum observa\u021bi, toate evenimentele care au venit \u00een ultimele 20 de secunde sunt incluse \u00een fereastr\u0103. La sf\u00e2r\u0219itul acestui interval, se creeaz\u0103 o nou\u0103 fereastr\u0103.<\/p>\n<p>\u00cen listarea 5.6 este prezentat codul care demonstreaz\u0103 utilizarea feron\u021belor \u201etumbling\u201d pentru a captura tranzac\u021biile bursiere la fiecare 20 de secunde (acesta poate fi g\u0103sit \u00een fi\u0219ierul src\/main\/java\/bbejeck\/chapter_5\/CountingWindowingAndKtableJoinExample.java).<\/p>\n<p><img decoding=\"async\" alt=\"Cartea \u201eKafka Streams \u00een ac\u021biune. Aplica\u021bii \u0219i microservicii pentru lucru \u00een timp real\u201d\" src=\"\/wp-content\/uploads\/e055bb1b288c7d500b64372fe3fbf064.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDatorit\u0103 acestei mici modific\u0103ri a apelului metodei TimeWindows.of, se poate utiliza o fereastr\u0103 \u201etumbling\u201d. \u00cen acest exemplu nu exist\u0103 apelul metodei until(), ceea ce va folosi intervalul de reten\u021bie implicit, de 24 de ore.<\/p>\n<p>\u00cen cele din urm\u0103, este timpul s\u0103 trecem la ultima op\u021biune de feron\u021be \u2014 feron\u021bele \u201ehopping\u201d.<\/p>\n<h3>Feron\u021bele \u201esliding\u201d\/\u201ehopping\u201d<\/h3>\n<p>\nFeron\u021bele \u201esliding\u201d\/\u201ehopping\u201d sunt asem\u0103n\u0103toare cu cele \u201etumbling\u201d, dar cu o mic\u0103 diferen\u021b\u0103. Feron\u021bele \u201esliding\u201d nu a\u0219teapt\u0103 sf\u00e2r\u0219itul intervalului de timp \u00eenainte de a crea o nou\u0103 fereastr\u0103 pentru a procesa evenimentele recente. Ele initializeaz\u0103 noi calcule dup\u0103 un interval de a\u0219teptare mai mic dec\u00e2t durata feron\u021bei.<\/p>\n<p>Pentru a ilustra diferen\u021bele dintre feron\u021bele \u201etumbling\u201d \u0219i \u201ehopping\u201d, s\u0103 ne \u00eentoarcem la exemplul cu num\u0103rarea tranzac\u021biilor bursiere. Scopul nostru r\u0103m\u00e2ne acela de a num\u0103ra tranzac\u021biile, dar nu dorim s\u0103 a\u0219tept\u0103m \u00eentregul interval de timp \u00eenainte de a actualiza contorul. \u00cen schimb, vom actualiza contorul la intervale de timp mai scurte. De exemplu, vom continua s\u0103 num\u0103r\u0103m tranzac\u021biile la fiecare 20 de secunde, dar vom actualiza contorul la fiecare 5 secunde, a\u0219a cum se arat\u0103 \u00een figura 5.15. Astfel, vom avea trei feron\u021be de rezultat cu date suprapuse.<\/p>\n<p><img decoding=\"async\" alt=\"Cartea \u201eKafka Streams \u00een ac\u021biune. Aplica\u021bii \u0219i microservicii pentru lucru \u00een timp real\u201d\" src=\"\/wp-content\/uploads\/415c8cd9f2b60d453a1a01c3bc99331f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n\u00cen listarea 5.7 este prezentat codul pentru definirea feron\u021belor \u201esliding\u201d (acesta poate fi g\u0103sit \u00een fi\u0219ierul src\/main\/java\/bbejeck\/chapter_5\/CountingWindowingAndKtableJoinExample.java).<\/p>\n<p><img decoding=\"async\" alt=\"Cartea \u201eKafka Streams \u00een ac\u021biune. Aplica\u021bii \u0219i microservicii pentru lucru \u00een timp real\u201d\" src=\"\/wp-content\/uploads\/ab2d1a64380d256d3fb084e16597417c.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nFereastra \u201ecare se r\u0103stoarn\u0103\u201d poate fi transformat\u0103 \u00eentr-o \u201efereastr\u0103 care sare\u201d prin ad\u0103ugarea apelului metodei advanceBy(). \u00cen exemplul dat, intervalul de salvare este de 15 minute.<\/p>\n<p>\u00cen aceast\u0103 sec\u021biune, a\u021bi v\u0103zut cum s\u0103 restric\u021biona\u021bi rezultatele agreg\u0103rii prin feron\u021biile temporale. \u00cen special, ar trebui s\u0103 re\u021bine\u021bi din aceast\u0103 sec\u021biune urm\u0103toarele trei lucruri:<\/p>\n<ul>\n<li>dimensiunea feron\u021biilor este limitat\u0103 nu de intervalul de timp, ci de activitatea utilizatorilor;<\/li>\n<li>feron\u021biile \u201ecare se r\u0103stoarn\u0103\u201d ofer\u0103 o imagine de ansamblu a evenimentelor pe parcursul unui interval de timp dat;<\/li>\n<li>durata feron\u021biilor \u201ecare sar\u201d este fix\u0103, dar acestea sunt adesea actualizate \u0219i pot con\u021bine \u00een toate feron\u021biile \u00eenregistr\u0103ri care se intersecteaz\u0103.<\/li>\n<\/ul>\n<p>\n\u00cen continuare, vom \u00eenv\u0103\u021ba cum s\u0103 transform\u0103m KTable \u00eenapoi \u00een KStream pentru a le conecta.<\/p>\n<h3>5.3.3. Conectarea obiectelor KStream \u0219i KTable<\/h3>\n<p>\n\u00cen capitolul 4 am discutat despre conectarea a dou\u0103 obiecte KStream. Acum va trebui s\u0103 \u00eenv\u0103\u021b\u0103m s\u0103 conect\u0103m KTable \u0219i KStream. Asta ar putea fi necesar din urm\u0103torul motiv simplu. KStream este un flux de \u00eenregistr\u0103ri, iar KTable este un flux de actualiz\u0103ri ale \u00eenregistr\u0103rilor, dar uneori ar putea fi nevoie s\u0103 ad\u0103ug\u0103m un context suplimentar fluxului de \u00eenregistr\u0103ri utiliz\u00e2nd actualiz\u0103rile din KTable.<\/p>\n<p>Vom lua datele despre num\u0103rul de tranzac\u021bii bursiere \u0219i le vom conecta cu \u0219tirile bursiere pentru industriile corespunz\u0103toare. Iat\u0103 ce trebuie s\u0103 facem pentru a realiza acest lucru av\u00e2nd \u00een vedere codul deja existent.<\/p>\n<ol>\n<li>Transforma\u021bi obiectul KTable cu date despre num\u0103rul de tranzac\u021bii bursiere \u00eentr-un KStream, schimb\u00e2nd ulterior cheia cu o cheie care indic\u0103 industria corespunz\u0103toare acestui simbol bursier.<\/li>\n<li>Crea\u021bi un obiect KTable care cite\u0219te date dintr-un topic cu \u0219tiri bursiere. Acest nou KTable va fi categorizat pe industrii.<\/li>\n<li>Conecta\u021bi actualiz\u0103rile de \u0219tiri cu informa\u021biile despre num\u0103rul de tranzac\u021bii bursiere pe industrii.<\/li>\n<\/ol>\n<p>\nAcum s\u0103 vedem cum putem implementa acest plan de ac\u021biune.<\/p>\n<h3>Transformarea KTable \u00een KStream<\/h3>\n<p>\nPentru a transforma KTable \u00een KStream, trebuie s\u0103 face\u021bi urm\u0103toarele.<\/p>\n<ol>\n<li>Apela\u021bi metoda KTable.toStream().<\/li>\n<li>Folosind apelul metodei KStream.map, schimba\u021bi cheia cu denumirea industriei, dup\u0103 care extrage\u021bi din instan\u021ba Windowed obiectul TransactionSummary.<\/li>\n<\/ol>\n<p>\nVom lega aceste opera\u021bii \u00eentr-un lan\u021b \u00een felul urm\u0103tor (codul poate fi g\u0103sit \u00een fi\u0219ierul src\/main\/java\/bbejeck\/chapter_5\/CountingWindowingAndKtableJoinExample.java) (lista 5.8).<\/p>\n<p><img decoding=\"async\" alt=\"Cartea \u201eKafka Streams \u00een ac\u021biune. Aplica\u021bii \u0219i microservicii pentru lucru \u00een timp real\u201d\" src=\"\/wp-content\/uploads\/0d43c2650f6e66e2816ed383da3a29c2.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDeoarece efectu\u0103m opera\u021biunea KStream.map, reasignarea pentru instan\u021ba KStream returnat\u0103 se realizeaz\u0103 automat atunci c\u00e2nd este utilizat\u0103 \u00een conexiune.<\/p>\n<p>Am finalizat procesul de transformare, acum trebuie s\u0103 cre\u0103m un obiect KTable pentru a citi \u0219tirile bursiere.<\/p>\n<h3>Crearea unui KTable pentru \u0219tirile bursiere<\/h3>\n<p>\nDin fericire, pentru a crea obiectul KTable este suficient un singur r\u00e2nd de cod (acest cod poate fi g\u0103sit \u00een fi\u0219ierul src\/main\/java\/bbejeck\/chapter_5\/CountingWindowingAndKtableJoinExample.java) (listarea 5.9).<\/p>\n<p><img decoding=\"async\" alt=\"Cartea \u201eKafka Streams \u00een ac\u021biune. Aplica\u021bii \u0219i microservicii pentru lucru \u00een timp real\u201d\" src=\"\/wp-content\/uploads\/6e83a393fdc9ab74fda4cbdddddb5213.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nEste de men\u021bionat c\u0103 nu sunt necesare obiecte Serde, deoarece \u00een set\u0103ri se folosesc Serde pentru \u0219iruri de caractere. De asemenea, datorit\u0103 utiliz\u0103rii enumer\u0103rii EARLIEST, tabelul este umplut cu \u00eenregistr\u0103ri de la \u00eenceput.<\/p>\n<p>Acum putem trece la etapa final\u0103 \u2014 conexiunea.<\/p>\n<h3>Conectarea actualiz\u0103rilor de \u0219tiri cu datele despre num\u0103rul de tranzac\u021bii<\/h3>\n<p>\nCrearea conexiunii nu prezint\u0103 dificult\u0103\u021bi. Vom folosi o conexiune st\u00e2ng\u0103 \u00een cazul \u00een care nu exist\u0103 \u0219tiri bursiere pentru sectorul industrial corespunz\u0103tor (codul necesar poate fi g\u0103sit \u00een fi\u0219ierul src\/main\/java\/bbejeck\/chapter_5\/CountingWindowingAndKtableJoinExample.java) (listarea 5.10).<\/p>\n<p><img decoding=\"async\" alt=\"Cartea \u201eKafka Streams \u00een ac\u021biune. Aplica\u021bii \u0219i microservicii pentru lucru \u00een timp real\u201d\" src=\"\/wp-content\/uploads\/92ed70f98927d2f778ad14dbc2a5aa26.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nAcest operator leftJoin este destul de simplu. Spre deosebire de conexiunile din capitolul 4, metoda JoinWindow nu este utilizat\u0103, deoarece la realizarea conexiunii KStream-KTable pentru fiecare cheie \u00een KTable exist\u0103 doar o singur\u0103 \u00eenregistrare. Aceast\u0103 conexiune nu este limitat\u0103 \u00een timp: \u00eenregistrarea este ori prezent\u0103 \u00een KTable, ori nu. Concluzia principal\u0103: prin intermediul obiectelor KTable se pot \u00eembog\u0103\u021bi KStream-urile cu date de referin\u021b\u0103 mai pu\u021bin frecvent actualizate.<\/p>\n<p>Acum vom examina o metod\u0103 mai eficient\u0103 de \u00eembog\u0103\u021bire a evenimentelor din KStream.<\/p>\n<h3>5.3.4. Obiectele GlobalKTable<\/h3>\n<p>\nDup\u0103 cum a\u021bi \u00een\u021beles, exist\u0103 o necesitate de a \u00eembog\u0103\u021bi fluxurile de evenimente sau de a le ad\u0103uga context. \u00cen capitolul 4 a\u021bi v\u0103zut conexiuni \u00eentre dou\u0103 obiecte KStream, iar \u00een sec\u021biunea anterioar\u0103 \u2014 conexiunea KStream \u0219i KTable. \u00cen toate aceste cazuri este necesar\u0103 reasignarea fluxului de date c\u00e2nd se transform\u0103 cheile \u00eentr-un nou tip sau valoare. Uneori reasignarea se face explicit, iar alteori Kafka Streams o face automat. Reasignarea este necesar\u0103 deoarece cheile s-au schimbat \u0219i \u00eenregistr\u0103rile trebuie s\u0103 ajung\u0103 \u00een noi sec\u021biuni, altfel conexiunea devine imposibil\u0103 (acest lucru a fost discutat \u00een capitolul 4, \u00een punctul \u201eReasignarea datelor\u201d din subsec\u021biunea 4.2.4).<\/p>\n<h3>Repar\u021bionarea are un pre\u021b<\/h3>\n<p>\nRepar\u021bionarea necesit\u0103 costuri - costuri suplimentare de resurse pentru crearea de subiecte intermediare, p\u0103strarea datelor duplicat \u00eentr-un alt subiect; de asemenea, \u00eenseamn\u0103 o \u00eent\u00e2rziere mai mare din cauza scrierii \u0219i citirii din acest subiect. \u00cen plus, atunci c\u00e2nd este nevoie s\u0103 se efectueze o conexiune pe mai mult de un aspect sau dimensiune, trebuie s\u0103 se organizeze conexiuni \u00een lan\u021b, s\u0103 se mapese \u00eenregistr\u0103rile cu chei noi \u0219i s\u0103 se repete procesul de repar\u021bionare.<\/p>\n<h3>Conexiunea cu seturi de date mai mici<\/h3>\n<p>\n\u00cen unele cazuri, volumul de date de referin\u021b\u0103 cu care se planific\u0103 conectarea este relativ mic, astfel c\u0103 copiile lor complete pot \u00eenc\u0103pea local pe fiecare dintre noduri. Pentru astfel de situa\u021bii, \u00een Kafka Streams este prev\u0103zut\u0103 o clas\u0103 GlobalKTable.<\/p>\n<p>Instan\u021bele GlobalKTable sunt unice, deoarece aplica\u021bia replic\u0103 toate datele pe fiecare dintre noduri. \u0218i deoarece pe fiecare dintre noduri se afl\u0103 toate datele, nu este nevoie s\u0103 se repar\u021bioneze fluxul de evenimente pe cheia datelor de referin\u021b\u0103, astfel \u00eenc\u00e2t s\u0103 fie accesibil tuturor sec\u021biilor. Cu ajutorul obiectelor GlobalKTable se pot efectua, de asemenea, conexiuni f\u0103r\u0103 cheie. S\u0103 ne \u00eentoarcem la unul dintre exemplele anterioare pentru a demonstra aceast\u0103 capacitate.<\/p>\n<h3>Conectarea obiectelor KStream cu obiectele GlobalKTable<\/h3>\n<p>\n\u00cen subsec\u021biunea 5.3.2 am efectuat agregarea pe feroneri a tranzac\u021biilor bursiere pe clien\u021bi. Rezultatele acestei agreg\u0103ri ar\u0103tau cam a\u0219a:<\/p>\n<pre><code class=\"plaintext\">{customerId='074-09-3705', stockTicker='GUTM'}, 17\n{customerId='037-34-5184', stockTicker='CORK'}, 16<\/code><\/pre>\n<p>\nDe\u0219i aceste rezultate corespundeau obiectivului stabilit, ar fi fost mai convenabil dac\u0103 s-ar fi afi\u0219at \u0219i numele clientului \u0219i denumirea complet\u0103 a companiei. Pentru a ad\u0103uga numele clientului \u0219i denumirea companiei, se pot efectua conexiuni obi\u0219nuite, dar va fi necesar s\u0103 se fac\u0103 dou\u0103 map\u0103ri ale cheilor \u0219i s\u0103 se repete repar\u021bionarea. Cu ajutorul GlobalKTable se pot evita costurile pentru astfel de opera\u021biuni.<\/p>\n<p>Pentru aceasta, ne vom folosi de obiectul countStream din listingul 5.11 (codul corespunz\u0103tor poate fi g\u0103sit \u00een fi\u0219ierul src\/main\/java\/bbejeck\/chapter_5\/GlobalKTableExample.java), conect\u00e2ndu-l cu dou\u0103 obiecte GlobalKTable.<\/p>\n<p><img decoding=\"async\" alt=\"Cartea \u201eKafka Streams \u00een ac\u021biune. Aplica\u021bii \u0219i microservicii pentru lucru \u00een timp real\u201d\" src=\"\/wp-content\/uploads\/fc4d91bbe062ceb94f5650224840b81e.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nAm discutat despre acest lucru anterior, a\u0219a c\u0103 nu voi repeta. Totu\u0219i, vreau s\u0103 subliniez c\u0103 codul din func\u021bia toStream().map este abstractizat \u00eentr-o func\u021bie obiect pentru a \u00eembun\u0103t\u0103\u021bi lizibilitatea, \u00een loc de a folosi o expresie lambda \u00eencorporat\u0103.<\/p>\n<p>Urm\u0103torul pas este declararea a dou\u0103 instan\u021be GlobalKTable (codul respectiv poate fi g\u0103sit \u00een fi\u0219ierul src\/main\/java\/bbejeck\/chapter_5\/GlobalKTableExample.java) (listare 5.12).<\/p>\n<p><img decoding=\"async\" alt=\"Cartea \u201eKafka Streams \u00een ac\u021biune. Aplica\u021bii \u0219i microservicii pentru lucru \u00een timp real\u201d\" src=\"\/wp-content\/uploads\/db3918895f174c8cfb5fc927b55f87a1.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p>Re\u021bine\u021bi c\u0103 numele topicurilor sunt descrise folosind tipuri enumerate.<\/p>\n<p>Acum c\u0103 am preg\u0103tit toate componentele, trebuie s\u0103 scriem codul pentru \u00eembinare (care poate fi g\u0103sit \u00een fi\u0219ierul src\/main\/java\/bbejeck\/chapter_5\/GlobalKTableExample.java) (listare 5.13).<\/p>\n<p><img decoding=\"async\" alt=\"Cartea \u201eKafka Streams \u00een ac\u021biune. Aplica\u021bii \u0219i microservicii pentru lucru \u00een timp real\u201d\" src=\"\/wp-content\/uploads\/799360cc99f1920c190a61fd4685d4ff.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDe\u0219i \u00een acest cod sunt incluse dou\u0103 \u00eembin\u0103ri, acestea sunt organizate sub form\u0103 de lan\u021b, deoarece rezultatele lor nu sunt utilizate separat. Rezultatele sunt afi\u0219ate la sf\u00e2r\u0219itul \u00eentregii opera\u021biuni.<\/p>\n<p>C\u00e2nd rula\u021bi opera\u021biunea de mai sus, ve\u021bi ob\u021bine rezultate de forma urm\u0103toare:<\/p>\n<pre><code class=\"plaintext\">{customer='Barney, Smith' company=\"Exxon\", transactions= 17}<\/code><\/pre>\n<p>\nSubstan\u021ba nu s-a schimbat, dar aceste rezultate arat\u0103 mai clar.<\/p>\n<p>Dac\u0103 lua\u021bi \u00een considerare capitolul 4, a\u021bi v\u0103zut deja c\u00e2teva tipuri de \u00eembin\u0103ri \u00een ac\u021biune. Acestea sunt enumerate \u00een tab. 5.2. Aceast\u0103 tabel\u0103 reflect\u0103 capacit\u0103\u021bile de \u00eembinare relevante pentru versiunea 1.0.0 Kafka Streams; \u00een versiunile viitoare, este posibil s\u0103 se schimbe ceva.<\/p>\n<p><img decoding=\"async\" alt=\"Cartea \u201eKafka Streams \u00een ac\u021biune. Aplica\u021bii \u0219i microservicii pentru lucru \u00een timp real\u201d\" src=\"\/wp-content\/uploads\/8e4cf35c64a8431bda43a5e748de275f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n\u00cen concluzie, vreau s\u0103 v\u0103 reamintesc esen\u021bialul: pute\u021bi \u00eembina fluxuri de evenimente (KStream) \u0219i fluxuri de actualiz\u0103ri (KTable) folosind o stare local\u0103. \u00cen plus, dac\u0103 dimensiunea datelor de referin\u021b\u0103 nu este prea mare, pute\u021bi utiliza obiectul GlobalKTable. GlobalKTable replic\u0103 toate sec\u021biunile pe fiecare nod al aplica\u021biei Kafka Streams, asigur\u00e2nd astfel disponibilitatea tuturor datelor, indiferent de sec\u021biunea la care corespunde cheia.<\/p>\n<p>\u00cen continuare, vom explora capacitatea Kafka Streams care permite observarea modific\u0103rilor st\u0103rii f\u0103r\u0103 a consuma date din topicul Kafka.<\/p>\n<h3>5.3.5. Stare disponibil\u0103 pentru interogare<\/h3>\n<p>\nAm efectuat deja c\u00e2teva opera\u021biuni implic\u00e2nd stare \u0219i am afi\u0219at \u00eentotdeauna rezultatele \u00een consol\u0103 (\u00een scopuri de dezvoltare) sau le-am \u00eenregistrat \u00eentr-un topic (pentru scopuri de produc\u021bie). \u00cenregistr\u00e2nd rezultatele \u00eentr-un topic, este necesar s\u0103 folosi\u021bi un consumator Kafka pentru a le vizualiza.<\/p>\n<p>Citirea datelor din aceste subiecte poate fi considerat\u0103 o form\u0103 de vizualizare materializat\u0103 (materialized views). Pentru nevoile noastre, putem folosi defini\u021bia unei vizualiz\u0103ri materializate de pe Wikipedia: \u201e...un obiect fizic al bazei de date care con\u021bine rezultatele execu\u021biei unei interog\u0103ri. De exemplu, poate fi o copie local\u0103 a datelor \u00eendep\u0103rtate, sau un subset de r\u00e2nduri \u0219i\/sau coloane ale unei tabele sau rezultatelor unei combina\u021bii, sau un tabel de sumar ob\u021binut prin agregare\u201d (https:\/\/en.wikipedia.org\/wiki\/Materialized_view).<\/p>\n<p>Kafka Streams permite de asemenea efectuarea de interog\u0103ri interactive (interactive queries) asupra magazinelor de stare, ceea ce ofer\u0103 posibilitatea citirii directe a acestei vizualiz\u0103ri materializate. Este important de men\u021bionat c\u0103 interogarea magazinului de stare este o opera\u021bie \u201edoar pentru citire\u201d. Datorit\u0103 acestui lucru, nu trebuie s\u0103 v\u0103 face\u021bi griji c\u0103 ve\u021bi face starea inconsecvent\u0103 \u00een timpul proces\u0103rii datelor de c\u0103tre aplica\u021bie.<\/p>\n<p>Posibilitatea interog\u0103rilor directe asupra magazinelor de stare este foarte important\u0103. Aceasta \u00eenseamn\u0103 c\u0103 putem crea aplica\u021bii \u2014 tablouri de bord f\u0103r\u0103 a fi necesar s\u0103 ob\u021binem mai \u00eent\u00e2i datele de la consumatorul Kafka. De asemenea, \u00eembun\u0103t\u0103\u021be\u0219te eficien\u021ba aplica\u021biei, deoarece nu este necesar s\u0103 scriem din nou datele:<\/p>\n<ul>\n<li>datorit\u0103 localiz\u0103rii datelor, acestea pot fi accesate rapid;<\/li>\n<li>se exclude duplicarea datelor, deoarece acestea nu sunt scrise \u00een stocarea extern\u0103.<\/li>\n<\/ul>\n<p>\nCel mai important lucru pe care a\u0219 dori s\u0103-l re\u021bine\u021bi: pute\u021bi efectua interog\u0103ri direct la stare din aplica\u021bie. Nu poate fi subestimat\u0103 capacitatea pe care aceasta v-o ofer\u0103. \u00cen loc s\u0103 consuma\u021bi date din Kafka \u0219i s\u0103 salva\u021bi \u00eenregistr\u0103rile \u00eentr-o baz\u0103 de date pentru aplica\u021bie, pute\u021bi efectua interog\u0103ri asupra magazinelor de stare cu acela\u0219i rezultat. Interog\u0103rile directe la magazinele de stare \u00eenseamn\u0103 un volum mai mic de cod (f\u0103r\u0103 consumator) \u0219i mai pu\u021bin software (f\u0103r\u0103 necesitatea unei tabele de baze de date pentru a stoca rezultatele).<\/p>\n<p>Am acoperit o cantitate considerabil\u0103 de informa\u021bii \u00een acest capitol, a\u0219a c\u0103 vom \u00eentrerupe temporar discu\u021bia noastr\u0103 despre interog\u0103rile interactive la stoc\u0103rile de stare. Dar nu v\u0103 face\u021bi griji: \u00een capitolul 9 vom crea o aplica\u021bie simpl\u0103 - un panou de informare cu interog\u0103ri interactive. Pentru a demonstra interog\u0103rile interactive \u0219i posibilit\u0103\u021bile de a le integra \u00een aplica\u021biile Kafka Streams, vor fi utilizate unele dintre exemplele din acest capitol \u0219i cel anterior.<\/p>\n<h3>Rezumat<\/h3>\n<p><\/p>\n<ul>\n<li>Obiectele KStream reprezint\u0103 fluxuri de evenimente, comparabile cu inser\u021biile \u00eentr-o baz\u0103 de date. Obiectele KTable reprezint\u0103 fluxuri de actualiz\u0103ri, fiind mai asem\u0103n\u0103toare cu actualiz\u0103rile din baza de date. Dimensiunea unui obiect KTable nu cre\u0219te, \u00eenregistr\u0103rile vechi fiind \u00eenlocuite cu cele noi.<\/li>\n<li>Obiectele KTable sunt necesare pentru opera\u021bii de agregare.<\/li>\n<li>Prin opera\u021biile de fereastr\u0103, se pot grupa datele agregate \u00een co\u0219uri temporale.<\/li>\n<li>Datorit\u0103 obiectelor GlobalKTable, este posibil s\u0103 accesa\u021bi datele de referin\u021b\u0103 din orice punct al aplica\u021biei, indiferent de \u00eemp\u0103r\u021birea pe sec\u021biuni.<\/li>\n<li>Este posibil s\u0103 se fac\u0103 conexiuni \u00eentre obiectele KStream, KTable \u0219i GlobalKTable.<\/li>\n<\/ul>\n<p>\nP\u00e2n\u0103 acum, ne-am concentrat asupra cre\u0103rii de aplica\u021bii Kafka Streams prin intermediul DSL-ului KStream de nivel \u00eenalt. De\u0219i abordarea de nivel \u00eenalt permite crearea de programe curate \u0219i concise, utilizarea sa reprezint\u0103 un compromis. Lucrul cu DSL-ul KStream \u00eenseamn\u0103 sporirea conciziei codului \u00een detrimentul controlului. \u00cen capitolul urm\u0103tor, vom explora API-ul de nivel sc\u0103zut al nodurilor de procesare \u0219i vom analiza alte compromisuri. Programele vor deveni mai lungi dec\u00e2t erau p\u00e2n\u0103 acum, dar vom avea oportunitatea de a crea practic orice nod de procesare de care am avea nevoie.<\/p>\n<p>\u2192 Pute\u021bi citi mai multe despre carte la <noindex><a rel=\"nofollow\" href=\"https:\/\/www.piter.com\/collection\/best\/product\/kafka-streams-v-deystvii-prilozheniya-i-mikroservisy-dlya-raboty-v-realnom-vremeni\">site-ul editurii<\/a><\/noindex><\/p>\n<p>\u2192 Pentru utilizatorii Habr, un discount de 25% cu cupoane - <b>Kafka Streams<\/b><\/p>\n<p>\u2192 Dup\u0103 plata versiunii tip\u0103rite a c\u0103r\u021bii, o carte electronic\u0103 va fi trimis\u0103 pe e-mail.<br \/>\n<br \/>Sursa: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/piter\/blog\/457756\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440\u043e\u0436\u0438\u0442\u0435\u043b\u0438! \u042d\u0442\u0430 \u043a\u043d\u0438\u0433\u0430 \u043f\u043e\u0434\u043e\u0439\u0434\u0435\u0442 \u0434\u043b\u044f \u043b\u044e\u0431\u043e\u0433\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0445\u043e\u0447\u0435\u0442 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0432 \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435. \u041f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043b\u0443\u0447\u0448\u0435 \u0438\u0437\u0443\u0447\u0438\u0442\u044c Kafka \u0438 Kafka Streams. \u0411\u044b\u043b\u043e \u0431\u044b \u043d\u0435\u043f\u043b\u043e\u0445\u043e \u0437\u043d\u0430\u0442\u044c \u0438 \u0441\u0430\u043c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a Kafka, \u043d\u043e \u044d\u0442\u043e \u043d\u0435 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e: \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u0432\u0430\u043c \u0432\u0441\u0435, \u0447\u0442\u043e \u043d\u0443\u0436\u043d\u043e. \u041e\u043f\u044b\u0442\u043d\u044b\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 Kafka, \u043a\u0430\u043a \u0438 \u043d\u043e\u0432\u0438\u0447\u043a\u0438, \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u044d\u0442\u043e\u0439 \u043a\u043d\u0438\u0433\u0435 \u043e\u0441\u0432\u043e\u044f\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-35786","post","type-post","status-publish","format-standard","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.4 - aioseo.com -->\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/kniga-kafka-streams-v-dejstvii-prilozheniya-i-mikroservisy-dlya-raboty-v-realnom-vremeni\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.4\" \/>\n\t\t<meta property=\"og:locale\" content=\"ro_RO\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u041a\u043d\u0438\u0433\u0430 \u00abKafka Streams \u0432 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0438. \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u044b \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438\u00bb | ProHoster\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/kniga-kafka-streams-v-dejstvii-prilozheniya-i-mikroservisy-dlya-raboty-v-realnom-vremeni\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T19:06:19+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T19:06:19+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Cartea \u201eKafka Streams \u00een ac\u021biune. Aplica\u021bii \u0219i microservicii pentru operare \u00een timp real\u201d | ProHoster","description":"","canonical_url":"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/kniga-kafka-streams-v-dejstvii-prilozheniya-i-mikroservisy-dlya-raboty-v-realnom-vremeni","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"ro_RO","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u041a\u043d\u0438\u0433\u0430 \u00abKafka Streams \u0432 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0438. \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u044b \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438\u00bb | ProHoster","og:url":"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/kniga-kafka-streams-v-dejstvii-prilozheniya-i-mikroservisy-dlya-raboty-v-realnom-vremeni","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T19:06:19+00:00","article:modified_time":"2019-10-31T19:06:19+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"35786","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-22 00:45:19","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 01:56:32","updated":"2026-01-22 00:45:19","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts\/35786","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/comments?post=35786"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts\/35786\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/media?parent=35786"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/categories?post=35786"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/tags?post=35786"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}