{"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\/hr\/blog\/administrirovanie\/kniga-kafka-streams-v-dejstvii-prilozheniya-i-mikroservisy-dlya-raboty-v-realnom-vremeni","title":{"rendered":"Knjiga \u201eKafka Streams u akciji. Aplikacije i mikroslu\u017ebe za rad u stvarnom vremenu\u201c","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=\"Knjiga \u201eKafka Streams u akciji. Aplikacije i mikroslu\u017ebe za rad u stvarnom vremenu\u201c\" src=\"\/wp-content\/uploads\/6f8bd2b31b87b0c760c1148515893c43.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex> Pozdrav, Habrovi! Ova knjiga je pogodna za svakog programera koji \u017eeli razumjeti obradu podataka u stvarnom vremenu. Razumijevanje distribuiranog programiranja pomo\u0107i \u0107e vam bolje prou\u010diti Kafka i Kafka Streams. Bilo bi dobro poznavati i sam framework Kafka, no to nije obavezno: re\u0107i \u0107u vam sve \u0161to trebate znati. Iskusni programeri Kafke, kao i po\u010detnici, zahvaljuju\u0107i ovoj knjizi nau\u010dit \u0107e kako stvoriti zanimljive aplikacije za obradu podataka s bibliotekom Kafka Streams. Java programeri srednje i visoke razine, koji su ve\u0107 navikli na takve pojmove kao \u0161to je serijalizacija, nau\u010dit \u0107e primjenjivati svoje vje\u0161tine za izradu aplikacija Kafka Streams. Izvorni kod knjige napisan je na Javi 8 i zna\u010dajno koristi sintaksu lambda izraza Jave 8, stoga \u0107e vam znanje rada s lambda funkcijama (\u010dak i na drugom programskom jeziku) biti od koristi.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h3>Isje\u010dak. 5.3. Agregacija i prozorske operacije<\/h3>\n<p>\nU ovom odjeljku prelazimo na prou\u010davanje najperspektivnijih dijelova Kafka Streams. Do sada smo razmotrili sljede\u0107e aspekte Kafka Streams:<\/p>\n<ul>\n<li>kreiranje topologije obrade;<\/li>\n<li>kori\u0161tenje stanja u aplikacijama za obradu podataka;<\/li>\n<li>izvr\u0161avanje spajanja tokova podataka;<\/li>\n<li>razlike izme\u0111u tokova doga\u0111aja (KStream) i tokova a\u017euriranja (KTable).<\/li>\n<\/ul>\n<p>\nU sljede\u0107im primjerima spojit \u0107emo sve te elemente zajedno. Osim toga, upoznat \u0107ete se s prozorskim operacijama \u2014 jo\u0161 jednom izvrsnom mogu\u0107no\u0161\u0107u aplikacija za obradu podataka. Na\u0161 prvi primjer bit \u0107e jednostavna agregacija.<\/p>\n<h3>5.3.1. Agregacija volumena prodaje dionica po industrijama<\/h3>\n<p>\nAgregacija i grupiranje su od vitalne va\u017enosti pri radu s podacima u stvarnom vremenu. Istra\u017eivanje pojedinih zapisa dok dolaze \u010desto se pokazuje nedovoljnim. Kako biste iz podataka izvukli dodatne informacije, potrebni su grupiranje i kombiniranje.<\/p>\n<p>U ovom primjeru trebat \u0107ete preuzeti ulogu intra-dnevnog trgovca koji treba pratiti volumene prodaje dionica kompanija u nekoliko industrija. Konkretno, zanimaju vas pet kompanija s najve\u0107im volumenima prodaje dionica u svakoj industriji.<\/p>\n<p>Za takvu agregaciju bit \u0107e potrebno nekoliko sljede\u0107ih koraka za pretvorbu podataka u \u017eeljeni oblik (ako govorimo u op\u0107im crtama).<\/p>\n<ol>\n<li>Stvorite izvor temeljen na temi koji objavljuje neobra\u0111ene informacije o trgovini dionicama. Morat \u0107emo prikazati objekt tipa StockTransaction u objekt tipa ShareVolume. Naime, objekt StockTransaction sadr\u017ei metapodatke prodaje, dok su nam potrebni samo podaci o broju prodanih dionica.<\/li>\n<li>Grupirajte podatke ShareVolume po simbolima dionica. Nakon grupiranja po simbolima, mo\u017eete smanjiti te podatke na me\u0111uzbroj volumena prodaje dionica. Vrijedi napomenuti da metoda KStream.groupBy vra\u0107a instancu tipa KGroupedStream. A da biste dobili instancu KTable, morate dalje pozvati metodu KGroupedStream.reduce.<\/li>\n<\/ol>\n<p><\/p>\n<blockquote><p><b>\u0160to je KGroupedStream su\u010delje?<\/b><\/p>\n<p>Metode KStream.groupBy i KStream.groupByKey vra\u0107aju instancu KGroupedStream. KGroupedStream je me\u0111urezultatska reprezentacija toka doga\u0111aja nakon grupiranja po klju\u010devima. Nije namijenjena izravnom radu s njom. Umjesto toga, KGroupedStream se koristi za operacije agregacije, \u010diji rezultat uvijek predstavlja KTable. Kako su rezultati operacija agregacije KTable i koriste pohranu stanja, mogu\u0107e je da ne\u0107e sve promjene rezultata biti poslane dalje kroz cjevovod.<\/p>\n<p>Metoda KTable.groupBy vra\u0107a sli\u010dan KGroupedTable \u2014 me\u0111urezultatsku reprezentaciju toka a\u017euriranja, reorganiziranih po klju\u010du.<\/p><\/blockquote>\n<p>\nNapravimo kratku pauzu i pogledajmo sliku 5.9, koja pokazuje \u0161to smo postigli. Ova topologija bi vam ve\u0107 trebala biti dobro poznata.<\/p>\n<p><img decoding=\"async\" alt=\"Knjiga \u201eKafka Streams u akciji. Aplikacije i mikroslu\u017ebe za rad u stvarnom vremenu\u201c\" src=\"\/wp-content\/uploads\/9fd61317cde376362adcaeec72908919.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nPogledajmo sada kod za ovu topologiju (mo\u017eete ga prona\u0107i u datoteci src\/main\/java\/bbejeck\/chapter_5\/AggregationsAndReducingExample.java) (popis 5.2).<\/p>\n<p><img decoding=\"async\" alt=\"Knjiga \u201eKafka Streams u akciji. Aplikacije i mikroslu\u017ebe za rad u stvarnom vremenu\u201c\" src=\"\/wp-content\/uploads\/f937287e448295fbd467c283ceca316a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nPrikazani kod odlikuje se sa\u017eetost i velikom koli\u010dinom akcija provedenih u nekoliko redaka. U prvom parametru metode builder.stream mo\u017eete primijetiti ne\u0161to novo za vas: vrijednost enumeriranog tipa AutoOffsetReset.EARLIEST (postoji tako\u0111er i LATEST), koja se postavlja pomo\u0107u metode Consumed.withOffsetResetPolicy. Ova enumeracija omogu\u0107uje da odredite strategiju ponovnog postavljanja offset-a za svaki KStream ili KTable, ona ima prioritet nad parametrom ponovnog postavljanja offset-a iz konfiguracije.<\/p>\n<blockquote><p><b>GroupByKey i GroupBy<\/b><\/p>\n<p>U su\u010delju KStream postoje dvije metode za grupiranje zapisa: GroupByKey i GroupBy. Obje vra\u0107aju KGroupedTable, pa se mo\u017ee postaviti pitanje: koja je razlika izme\u0111u njih i kada koristiti koju?<\/p>\n<p>Metoda GroupByKey se primjenjuje kada su klju\u010devi u KStream ve\u0107 popunjeni. A najva\u017enije, oznaka \" zahtijeva ponovnu particionaciju\" nikada nije postavljena.<\/p>\n<p>Metoda GroupBy podrazumjeva da ste promijenili klju\u010deve za grupiranje, tako da je oznaka ponovne particionacije postavljena na true. Izvr\u0161enje nakon metode GroupBy spojeva, agregacija itd. rezultirat \u0107e automatskom ponovnom particionacijom.<br \/>\nZaklju\u010dak: potrebno je iskoristiti GroupByKey umjesto GroupBy kad god je to mogu\u0107e.<\/p><\/blockquote>\n<p>\n\u0160to metode mapValues i groupBy rade \u2014 jasno je, pa pogledajmo metodu sum() (mo\u017ee se prona\u0107i u datoteci src\/main\/java\/bbejeck\/model\/ShareVolume.java) (listing 5.3).<\/p>\n<p><img decoding=\"async\" alt=\"Knjiga \u201eKafka Streams u akciji. Aplikacije i mikroslu\u017ebe za rad u stvarnom vremenu\u201c\" src=\"\/wp-content\/uploads\/8e9a6f873594f9b5fef9a96c42353a61.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMetoda ShareVolume.sum vra\u0107a privremenu sumu volumena prodaje dionica, dok je rezultat cijelog niza izra\u010duna objekt KTable. Sada razumijete koju ulogu igra KTable. Kada objekti ShareVolume stignu, u odgovaraju\u0107em objektu KTable se pohranjuje posljednje a\u017euriranje. Va\u017eno je ne zaboraviti da se sva a\u017euriranja odra\u017eavaju u prethodnom shareVolumeKTable, ali ne \u0161alju se svi dalje.<\/p>\n<p>Dalje, pomo\u0107u ovog KTable-a izvr\u0161avamo agregaciju (po broju prodanih dionica) kako bismo dobili pet kompanija s najve\u0107im volumenom prodaje dionica u svakoj industriji. Na\u0161e radnje \u0107e biti sli\u010dne onima u prvoj agregaciji.<\/p>\n<ol>\n<li>Izvr\u0161ite jo\u0161 jednu operaciju groupBy za grupiranje pojedina\u010dnih objekata ShareVolume prema industrijama.<\/li>\n<li>Po\u010dnite sa zbrajanjem objekata ShareVolume. Ovaj put objekt agregiranja predstavlja red s prioritetom fiksne veli\u010dine. U takvom redu fiksne veli\u010dine pohranjuju se samo pet kompanija s najve\u0107im brojem prodanih dionica.<\/li>\n<li>Prika\u017eite redove iz prethodne to\u010dke u string vrijednosti i vratite pet najprodavanijih prema broju dionica po industrijama.<\/li>\n<li>Zapi\u0161ite rezultate u string formatu u temu.<\/li>\n<\/ol>\n<p>\nNa slici 5.10 prikazan je graf topologije kretanja podataka. Kao \u0161to vidite, drugi ciklus obrade je prili\u010dno jednostavan.<\/p>\n<p><img decoding=\"async\" alt=\"Knjiga \u201eKafka Streams u akciji. Aplikacije i mikroslu\u017ebe za rad u stvarnom vremenu\u201c\" src=\"\/wp-content\/uploads\/dabd1507eee267038edb7f8d76d8d8ae.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nSada, jasno shvativ\u0161i strukturu ovog drugog ciklusa obrade, mo\u017eete se obratiti njegovom izvoru (na\u0107i \u0107ete ga u datoteci src\/main\/java\/bbejeck\/chapter_5\/AggregationsAndReducingExample.java) (listing 5.4).<\/p>\n<p>U ovom inicijalizatoru postoji varijabla fixedQueue. To je prilago\u0111eni objekt \u2014 adapter za java.util.TreeSet, koji se koristi za pra\u0107enje N najve\u0107ih rezultata po opadaju\u0107em redoslijedu broja prodanih dionica.<\/p>\n<p><img decoding=\"async\" alt=\"Knjiga \u201eKafka Streams u akciji. Aplikacije i mikroslu\u017ebe za rad u stvarnom vremenu\u201c\" src=\"\/wp-content\/uploads\/488b072b0d91b81c925ca72291e69e48.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nVe\u0107 ste se susreli s pozivima groupBy i mapValues, pa se ne\u0107emo zadr\u017eavati na njima (pozivamo metodu KTable.toStream, jer se smatralo da je metoda KTable.print zastarjela). Me\u0111utim, jo\u0161 niste vidjeli KTable verziju metode aggregate(), tako da \u0107emo potro\u0161iti malo vremena na njezino razmatranje.<\/p>\n<p>Kao \u0161to se sje\u0107ate, KTable se razlikuje po tome \u0161to se zapisi s istim klju\u010devima smatraju a\u017euriranjima. KTable zamjenjuje stari zapis novim. Agregacija se odvija na sli\u010dan na\u010din: agregiraju se najnoviji zapisi s istim klju\u010dem. Kada novi zapis do\u0111e, dodaje se u instancu klase FixedSizePriorityQueue pomo\u0107u sumatora (drugi parametar u pozivu metode aggregate), ali ako ve\u0107 postoji drugi zapis s istim klju\u010dem, stari zapis se uklanja pomo\u0107u oduzima\u010da (tre\u0107i parametar u pozivu metode aggregate).<\/p>\n<p>To sve zna\u010di da na\u0161 agregator, FixedSizePriorityQueue, ne agregira sve vrijednosti s istim klju\u010dem, ve\u0107 \u010duva klizni zbroj koli\u010dina N najprodavanijih vrsta dionica. U svakom novom zapisu nalazi se ukupna koli\u010dina prodanih dionica do sada. KTable \u0107e vam dati informacije o tome koje se dionice kojih kompanija trenutno najvi\u0161e prodaju, a klizno agregiranje svake od a\u017euriranja nije potrebno.<\/p>\n<p>Nau\u010dili smo raditi dvije va\u017ene stvari:<\/p>\n<ul>\n<li>grupirati vrijednosti u KTable prema zajedni\u010dkom klju\u010du;<\/li>\n<li>provoditi nad tim grupiranim vrijednostima korisne operacije poput zbrajanja i agregacije.<\/li>\n<\/ul>\n<p>\nSposobnost izvo\u0111enja ovih operacija je va\u017ena za razumijevanje zna\u010denja podataka koji prolaze kroz aplikaciju Kafka Streams i otkrivanje koje informacije nose.<\/p>\n<p>Ujedinili smo nekoliko klju\u010dnih pojmova koji su ranije raspravljani u ovoj knjizi. U poglavlju 4 govorili smo koliko je va\u017eno imati otpornu, lokalnu stanje za aplikacije za streaming. Prvi primjer iz ovog poglavlja pokazao je za\u0161to je lokalno stanje od vitalnog zna\u010daja \u2014 omogu\u0107ava pra\u0107enje informacija koje ste ve\u0107 vidjeli. Lokalan pristup poma\u017ee u izbjegavanju mre\u017enih ka\u0161njenja, \u010dime aplikacija postaje u\u010dinkovitija i otpornija na gre\u0161ke.<\/p>\n<p>Prilikom izvo\u0111enja bilo koje operacije preklapanja ili agregacije potrebno je odrediti naziv skladi\u0161ta stanja. Operacije preklapanja i agregacije vra\u0107aju instancu KTable, a KTable koristi skladi\u0161te stanja za zamjenu starih rezultata novima. Kao \u0161to ste vidjeli, nije svaka a\u017euriranja poslana dalje kroz cijev, \u0161to je va\u017eno jer su operacije agregacije namijenjene dobivanju kona\u010dnih informacija. Ako se ne koristi lokalno stanje, KTable \u0107e slati dalje sve rezultate agregacije i preklapanja.<\/p>\n<p>Sljede\u0107e \u0107emo razmotriti izvo\u0111enje operacija kao \u0161to su agregacija unutar odre\u0111enog vremenskog razdoblja \u2014 tzv. operacije prozora (windowing operations).<\/p>\n<h3>5.3.2. Operacije prozora<\/h3>\n<p>\nU prethodnom odjeljku upoznali smo se s \"kliznim\" preklapanjem i agregacijom. Aplikacija je neprekidno provodila preklapanje volumena prodaje dionica, nakon \u010dega se agregirao pet najprodavanijih dionica na burzi.<\/p>\n<p>Ponekad su ovakve neprekidne agregacije i preklapanja rezultata potrebne. A ponekad je potrebno izvr\u0161iti operacije samo za odre\u0111eno vremensko razdoblje. Na primjer, izra\u010dunati koliko je burzovnih transakcija s dionicama odre\u0111ene kompanije izvr\u0161eno u posljednjih 10 minuta. Ili koliko je korisnika kliknulo na novu reklamnu baner tijekom posljednjih 15 minuta. Aplikacija mo\u017ee izvr\u0161avati takve operacije vi\u0161e puta, ali s rezultatima koji se odnose samo na odre\u0111eno vremensko razdoblje (vremenska okna).<\/p>\n<h3>Brojanje burzovnih transakcija po kupcu<\/h3>\n<p>\nU sljede\u0107em primjeru bavimo se pra\u0107enjem burzovnih transakcija za nekoliko trgovaca \u2014 bilo za velike organizacije ili za snala\u017eljive financiste-samo\u0107e.<\/p>\n<p>Postoje dva mogu\u0107a razloga za ovo pra\u0107enje. Jedan od njih je potreba da se zna \u0161to kupuju\/prodaju tr\u017ei\u0161ni lideri. Ako ti veliki igra\u010di i iskusan investitori vide prilike za sebe, ima smisla slijediti njihove strategije. Drugi razlog je \u017eelja da se primijete bilo kakvi znakovi nezakonitih transakcija koriste\u0107i povjerljive informacije. Za to \u0107e vam biti potrebno analizirati korelaciju velikih porasta prodaje s va\u017enim priop\u0107enjima za medije.<\/p>\n<p>Takvo pra\u0107enje se sastoji od sljede\u0107ih faza:<\/p>\n<ul>\n<li>izrada toka za \u010ditanje iz topica stock-transactions;<\/li>\n<li>grupiranje ulaznih zapisa po identifikatoru kupca i simbolu dionice. Poziv metode groupBy vra\u0107a instancu klase KGroupedStream;<\/li>\n<li>vra\u0107anje metodom KGroupedStream.windowedBy toka podataka, ograni\u010denog vremenskim prozorom, \u0161to omogu\u0107uje obavljanje agregacije na prozoru. Ovisno o vrsti prozora, vra\u0107a se ili TimeWindowedKStream ili SessionWindowedKStream;<\/li>\n<li>brojanje transakcija za agregacijski operaciju. Prozorski tok podataka odre\u0111uje ho\u0107e li se odre\u0111eni zapis uzeti u obzir pri ovom brojanju;<\/li>\n<li>zapisivanje rezultata u topic ili ispisivanje na konzolu tijekom razvoja.<\/li>\n<\/ul>\n<p>\nTopologija ove aplikacije je jednostavna, ali pregledna slika ne bi na\u0161kodila. Pogledajmo sl. 5.11.<\/p>\n<p>Nakon toga \u0107emo razmotriti funkcionalnost prozorskih operacija i pripadaju\u0107i kod.<\/p>\n<p><img decoding=\"async\" alt=\"Knjiga \u201eKafka Streams u akciji. Aplikacije i mikroslu\u017ebe za rad u stvarnom vremenu\u201c\" src=\"\/wp-content\/uploads\/67d9d8d8acb1370a7c7fe5cd9a8b6aa7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h3>Tipovi prozora<\/h3>\n<p>\nU Kafka Streams postoje tri vrste prozora:<\/p>\n<ul>\n<li>sezonski;<\/li>\n<li>\u201eprevr\u0107u\u0107i\u201c (tumbling);<\/li>\n<li>klizni\/\u201eskaka\u010di\u201c (sliding\/hopping).<\/li>\n<\/ul>\n<p>\nKoji odabrati \u2014 ovisi o poslovnim zahtjevima. \u201ePrevr\u0107u\u0107i\u201c i \u201eskaka\u010di\u201c prozori su vremenski ograni\u010deni, dok su ograni\u010denja sezonskih prozora povezana s aktivnostima korisnika \u2014 trajanje sesije(-a) odre\u0111uje se isklju\u010divo pona\u0161anjem korisnika. Va\u017eno je ne zaboraviti da se svi tipovi prozora temelje na oznakama datuma\/vremena zapisa, a ne na sistemskom vremenu.<\/p>\n<p>Nakon toga \u0107emo implementirati na\u0161u topologiju za svaki od tipova prozora. Potpuni kod bit \u0107e naveden samo u prvom primjeru, dok za ostale tipove prozora ni\u0161ta ne\u0107e biti promijenjeno osim tipa prozorske operacije.<\/p>\n<h3>Sezonski prozori<\/h3>\n<p>\nProzori sesija se zna\u010dajno razlikuju od svih ostalih tipova prozora. Oni su ograni\u010deni ne toliko vremenom koliko aktivno\u0161\u0107u korisnika (ili aktivno\u0161\u0107u entiteta koji biste \u017eeleli pratiti). Prozori sesija se razdvajaju periodima neaktivnosti.<\/p>\n<p>Slika 5.12 ilustrira pojam prozora sesija. Manja sesija \u0107e se spojiti s sesijom lijevo od nje. Sesija desno \u0107e biti odvojena, jer slijedi dug period neaktivnosti. Prozori sesija se temelje na aktivnostima korisnika, ali koriste oznake datuma\/vremena iz zapisa za odre\u0111ivanje kojoj sesiji zapis pripada.<\/p>\n<p><img decoding=\"async\" alt=\"Knjiga \u201eKafka Streams u akciji. Aplikacije i mikroslu\u017ebe za rad u stvarnom vremenu\u201c\" src=\"\/wp-content\/uploads\/d39a5db7af7d6aa2194802622b2b47fd.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h3>Kori\u0161tenje prozora sesija za pra\u0107enje burzovnih transakcija<\/h3>\n<p>\nIskoristit \u0107emo prozore sesija za zadr\u017eavanje informacija o burzovnim transakcijama. Implementacija prozora sesija prikazana je u popisu 5.5 (koji se mo\u017ee prona\u0107i u datoteci src\/main\/java\/bbejeck\/chapter_5\/CountingWindowingAndKTableJoinExample.java).<\/p>\n<p><img decoding=\"async\" alt=\"Knjiga \u201eKafka Streams u akciji. Aplikacije i mikroslu\u017ebe za rad u stvarnom vremenu\u201c\" src=\"\/wp-content\/uploads\/2dcbd9a36baec0e746aad165121451b3.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nVe\u0107inu operacija ove topologije ste ve\u0107 susreli, tako da nema potrebe da ih ponovo razmatramo. No, ovdje postoje i neki novi elementi koje \u0107emo sada raspraviti.<\/p>\n<p>Prilikom svake operacije groupBy obi\u010dno se vr\u0161i neka operacija agregacije (agregacija, kompresija ili prebrojavanje). Mo\u017ee se provesti akumulativna agregacija s teku\u0107im zbrojem, ili prozorska agregacija, pri \u010demu se uzimaju u obzir zapisi unutar odre\u0111enog vremenskog prozora.<\/p>\n<p>Kod iz popisa 5.5 broji broj transakcija unutar prozora sesija. Na slici 5.13 te se radnje analiziraju korak po korak.<\/p>\n<p>Pozivom windowedBy(SessionWindows.with(twentySeconds).until(fifteenMinutes)) stvaramo prozor sesija s intervalom neaktivnosti od 20 sekundi i intervalom zadr\u017eavanja od 15 minuta. Interval neaktivnosti od 20 sekundi zna\u010di da \u0107e aplikacija uklju\u010diti svaki zapis koji do\u0111e unutar 20 sekundi od zavr\u0161etka ili po\u010detka trenutne sesije u trenutnu (aktivnu) sesiju.<\/p>\n<p><img decoding=\"async\" alt=\"Knjiga \u201eKafka Streams u akciji. Aplikacije i mikroslu\u017ebe za rad u stvarnom vremenu\u201c\" src=\"\/wp-content\/uploads\/9bd47b04698086872fd135b4c67eb938.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDalje navodimo koju operaciju agregacije treba izvr\u0161iti u sesijskom prozoru \u2014 u ovom slu\u010daju count. Ako ulazni zapis ispadne izvan granica intervala neaktivnosti (s bilo koje strane od oznake vremena), aplikacija stvara novu sesiju. Interval zadr\u017eavanja zna\u010di odr\u017eavanje sesije odre\u0111eno vrijeme i omogu\u0107ava ka\u0161njenje podataka koji izlaze iz razdoblja neaktivnosti sesije, ali se jo\u0161 uvijek mogu pridru\u017eiti. Osim toga, po\u010detak i kraj nove sesije koja nastaje spajanjem odgovaraju najranijoj i najkasnijoj oznaci vremena.<\/p>\n<p>Razmotrite nekoliko zapisa iz metode count kako bismo vidjeli kako funkcioni\u0161u sesije (tab. 5.1).<\/p>\n<p><img decoding=\"async\" alt=\"Knjiga \u201eKafka Streams u akciji. Aplikacije i mikroslu\u017ebe za rad u stvarnom vremenu\u201c\" src=\"\/wp-content\/uploads\/ec04aae466d88c2d2349474069c8d541.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nKada stignu zapisi, tra\u017eimo ve\u0107 postoje\u0107e sesije sa istim klju\u010dem, koje zavr\u0161avaju manje od trenutne oznake vremena \u2014 interval neaktivnosti i koje po\u010dinju vi\u0161e od trenutne oznake vremena + interval neaktivnosti. Uzimaju\u0107i to u obzir, \u010detiri zapisa iz tab. 5.1 spajaju se u jednu sesiju na sljede\u0107i na\u010din.<\/p>\n<p>1. Prvo dolazi zapis 1, tako da je vrijeme po\u010detka jednako vremenu zavr\u0161etka i iznosi 00:00:00.<\/p>\n<p>2. Zatim dolazi zapis 2, i tra\u017eimo sesije koje se zavr\u0161avaju najkasnije u 23:59:55 i po\u010dinju najkasnije u 00:00:35. Nalazimo zapis 1 i spajamo sesije 1 i 2. Uzimamo vrijeme po\u010detka sesije 1 (ranije) i vrijeme zavr\u0161etka sesije 2 (kasnije), tako da na\u0161a nova sesija po\u010dinje u 00:00:00 i zavr\u0161ava u 00:00:15.<\/p>\n<p>3. Dolazi zapis 3, tra\u017eimo sesije izme\u0111u 00:00:30 i 00:01:10 i ne nalazimo nijednu. Dodajemo drugu sesiju za klju\u010d 123-345-654,FFBE, koja po\u010dinje i zavr\u0161ava u 00:00:50.<\/p>\n<p>4. Dolazi zapis 4, i tra\u017eimo sesije izme\u0111u 23:59:45 i 00:00:25. Ovaj put nalazimo obje sesije \u2014 1 i 2. Sve tri sesije spajaju se u jednu, s vremenom po\u010detka 00:00:00 i vremenom zavr\u0161etka 00:00:15.<\/p>\n<p>Iz iznetog u ovom poglavlju treba zapamtiti sljede\u0107e va\u017ene nijanse:<\/p>\n<ul>\n<li>sesije nisu prozori fiksne veli\u010dine. Trajanje sesije odre\u0111uje se aktivno\u0161\u0107u unutar zadanog vremenskog okvira;<\/li>\n<li>oznake vremena u podacima odre\u0111uju ulazi li doga\u0111aj u postoje\u0107u sesiju ili u razdoblje neaktivnosti.<\/li>\n<\/ul>\n<p>\nDalje \u0107emo razgovarati o sljede\u0107em tipu prozora \u2014 \u201eprevrtaju\u0107i\u201d prozori.<\/p>\n<h3>\u201ePrevrtaju\u0107i\u201d prozori<\/h3>\n<p>\n\u201ePrevrnuta\u201c (tumbling) okna hvata doga\u0111aje koji se javljaju unutar odre\u0111enog vremenskog perioda. Zamislite da trebate zabilje\u017eiti sve burzovne transakcije neke tvrtke svake 20 sekundi, tako da prikupljate sve doga\u0111aje unutar tog vremenskog razdoblja. Na kraju od 20-sekundnog intervala, okno se \u201eprevr\u0107e\u201c i prelazi na novi 20-sekunda interval promatranja. Slika 5.14 ilustrira ovu situaciju.<\/p>\n<p><img decoding=\"async\" alt=\"Knjiga \u201eKafka Streams u akciji. Aplikacije i mikroslu\u017ebe za rad u stvarnom vremenu\u201c\" src=\"\/wp-content\/uploads\/e90e560d9ddda5e2e524b7c387ad9874.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nKao \u0161to mo\u017eete vidjeti, svi doga\u0111aji koji su se dogodili u posljednjih 20 sekundi uklju\u010deni su u okno. Nakon tog vremenskog perioda stvara se novo okno.<\/p>\n<p>U listingu 5.6 prikazan je kod koji demonstrira kori\u0161tenje \u201eprevrnutih\u201c okna za hvatanje burzovnih transakcija svake 20 sekundi (mo\u017eete ga prona\u0107i u datoteci src\/main\/java\/bbejeck\/chapter_5\/CountingWindowingAndKtableJoinExample.java).<\/p>\n<p><img decoding=\"async\" alt=\"Knjiga \u201eKafka Streams u akciji. Aplikacije i mikroslu\u017ebe za rad u stvarnom vremenu\u201c\" src=\"\/wp-content\/uploads\/e055bb1b288c7d500b64372fe3fbf064.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nZahvaljuju\u0107i ovoj maloj promjeni poziva metode TimeWindows.of mogu\u0107e je koristiti \u201eprevrnuto\u201c okno. U ovom primjeru nema poziva metode until(), zbog \u010dega \u0107e se koristiti zadani interval \u010duvanja od 24 sata.<\/p>\n<p>Na kraju, vrijeme je da pre\u0111emo na posljednju vrstu okna \u2014 \u201esko\u010dna\u201c (hopping) okna.<\/p>\n<h3>Sklizna (\u201esko\u010dna\u201c) okna<\/h3>\n<p>\nSklizna\/\u201esko\u010dna\u201c (sliding\/hopping) okna su sli\u010dna \u201eprevrnutim\u201c oknima, ali s malom razlikom. Sklizna okna ne \u010dekaju zavr\u0161etak vremenskog intervala prije nego \u0161to stvore novo okno za obradu nedavnih doga\u0111aja. Pokre\u0107u nove prora\u010dune nakon intervala \u010dekanja, koji je manji od trajanja okna.<\/p>\n<p>Za ilustraciju razlika izme\u0111u \u201eprevrnutih\u201c i \u201esko\u010dnih\u201c okna, vratimo se primjeru s brojanjem burzovnih transakcija. Na\u0161 cilj ostaje brojanje transakcija, ali ne \u017eelimo \u010dekati cijelo vremensko razdoblje prije nego \u0161to a\u017euriramo broja\u010d. Umjesto toga, a\u017eurirat \u0107emo broja\u010d u kra\u0107im vremenskim intervalima. Na primjer, i dalje \u0107emo brojati transakcije svake 20 sekundi, ali \u0107emo a\u017eurirati broja\u010d svake 5 sekundi, kao \u0161to je prikazano na slici 5.15. Na taj na\u010din imamo tri rezultatska okna s preklapaju\u0107im podacima.<\/p>\n<p><img decoding=\"async\" alt=\"Knjiga \u201eKafka Streams u akciji. Aplikacije i mikroslu\u017ebe za rad u stvarnom vremenu\u201c\" src=\"\/wp-content\/uploads\/415c8cd9f2b60d453a1a01c3bc99331f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nU listingu 5.7 prikazan je kod za definiranje skliznih okna (mo\u017eete ga prona\u0107i u datoteci src\/main\/java\/bbejeck\/chapter_5\/CountingWindowingAndKtableJoinExample.java).<\/p>\n<p><img decoding=\"async\" alt=\"Knjiga \u201eKafka Streams u akciji. Aplikacije i mikroslu\u017ebe za rad u stvarnom vremenu\u201c\" src=\"\/wp-content\/uploads\/ab2d1a64380d256d3fb084e16597417c.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nWindow that is 'rolling' can be transformed into a 'jumping' one by adding a call to the advanceBy() method. In the example provided, the retention interval is 15 minutes.<\/p>\n<p>In this section, you've seen how to limit aggregation results with time windows. Specifically, I would like you to remember the following three things from this section:<\/p>\n<ul>\n<li>the size of session windows is limited not by the time interval, but by user activity;<\/li>\n<li>'Rolling' windows provide insight into events over a specified period of time;<\/li>\n<li>the duration of 'jumping' windows is fixed, but they are frequently updated and can contain overlapping entries across all windows.<\/li>\n<\/ul>\n<p>\nNext, we will learn how to convert KTable back to KStream for joining.<\/p>\n<h3>5.3.3. Joining KStream and KTable objects<\/h3>\n<p>\nIn chapter 4, we discussed joining two KStream objects. Now we need to learn how to join KTable and KStream. This may be necessary for the following simple reason. KStream is a stream of records, while KTable is a stream of record updates, but sometimes additional context may need to be added to the stream of records using updates from KTable.<\/p>\n<p>Let's take the data on the number of stock transactions and join it with stock news relevant to the respective industries. Here\u2019s what needs to be done to achieve this considering the existing code.<\/p>\n<ol>\n<li>Convert the KTable object with the data on the number of stock transactions into KStream, replacing the key with the key representing the industry corresponding to that stock symbol.<\/li>\n<li>Create a KTable object that reads data from the topic with stock news. This new KTable will be categorized by industries.<\/li>\n<li>Join the news updates with information about the number of stock transactions by industries.<\/li>\n<\/ol>\n<p>\nNow let's see how to implement this action plan.<\/p>\n<h3>Converting KTable to KStream<\/h3>\n<p>\nTo convert KTable to KStream, the following steps need to be taken.<\/p>\n<ol>\n<li>Call the KTable.toStream() method.<\/li>\n<li>Using the KStream.map method call, replace the key with the name of the industry, and then extract the TransactionSummary object from the Windowed instance.<\/li>\n<\/ol>\n<p>\nWe will link these operations in the following chain (the code can be found in the file src\/main\/java\/bbejeck\/chapter_5\/CountingWindowingAndKtableJoinExample.java) (listing 5.8).<\/p>\n<p><img decoding=\"async\" alt=\"Knjiga \u201eKafka Streams u akciji. Aplikacije i mikroslu\u017ebe za rad u stvarnom vremenu\u201c\" src=\"\/wp-content\/uploads\/0d43c2650f6e66e2816ed383da3a29c2.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nBudu\u0107i da izvr\u0161avamo operaciju KStream.map, ponovno sekcioniranje za vra\u0107eni primjerak KStream-a automatski se vr\u0161i prilikom njegove upotrebe u spajanju.<\/p>\n<p>Zavr\u0161ili smo proces transformacije, sada moramo stvoriti objekt KTable za \u010ditanje burzovnih vijesti.<\/p>\n<h3>Stvaranje KTable za burzovne vijesti<\/h3>\n<p>\nNa sre\u0107u, za stvaranje objekta KTable dovoljna je samo jedna linija koda (ovaj kod mo\u017eete prona\u0107i u datoteci src\/main\/java\/bbejeck\/chapter_5\/CountingWindowingAndKtableJoinExample.java) (listing 5.9).<\/p>\n<p><img decoding=\"async\" alt=\"Knjiga \u201eKafka Streams u akciji. Aplikacije i mikroslu\u017ebe za rad u stvarnom vremenu\u201c\" src=\"\/wp-content\/uploads\/6e83a393fdc9ab74fda4cbdddddb5213.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nTreba napomenuti da nije potrebno navoditi nikakve Serde objekte, budu\u0107i da se koriste stringovni Serde u postavkama. Tako\u0111er, zahvaljuju\u0107i primjeni enumeracije EARLIEST, tablica se puni zapisima na samom po\u010detku.<\/p>\n<p>Sada se mo\u017eemo prebaciti na zavr\u0161ni korak \u2013 spajanje.<\/p>\n<h3>Spajanje a\u017euriranja vijesti s podacima o broju transakcija<\/h3>\n<p>\nStvaranje spajanja nije te\u0161ko. Iskoristit \u0107emo lijevo spajanje slu\u010daja kada u odgovaraju\u0107oj industriji nema burzovnih vijesti (potreban kod mo\u017eete prona\u0107i u datoteci src\/main\/java\/bbejeck\/chapter_5\/CountingWindowingAndKtableJoinExample.java) (listing 5.10).<\/p>\n<p><img decoding=\"async\" alt=\"Knjiga \u201eKafka Streams u akciji. Aplikacije i mikroslu\u017ebe za rad u stvarnom vremenu\u201c\" src=\"\/wp-content\/uploads\/92ed70f98927d2f778ad14dbc2a5aa26.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nOvaj operator leftJoin je prili\u010dno jednostavan. Za razliku od spajanja iz poglavlja 4, metoda JoinWindow se ne koristi, budu\u0107i da pri izvedbi spajanja KStream-KTable postoji samo jedan zapis za svaki klju\u010d u KTable. Ovo spajanje nije vremenski ograni\u010deno: zapis ili postoji u KTable ili ne postoji. Glavna poruka: putem objekta KTable mo\u017eete obogatiti KStream rje\u0111e a\u017euriranim referentnim podacima.<\/p>\n<p>A sada \u0107emo razmotriti u\u010dinkovitiji na\u010din oboga\u0107ivanja doga\u0111aja iz KStream-a.<\/p>\n<h3>5.3.4. Objekti GlobalKTable<\/h3>\n<p>\nKao \u0161to ste shvatili, postoji potreba za oboga\u0107ivanjem tokova doga\u0111aja ili dodavanjem konteksta. U poglavlju 4 ste vidjeli spajanje dvaju objekata KStream, a u prethodnom odjeljku \u2013 spajanje KStream-a i KTable-a. U svim tim slu\u010dajevima potrebno je ponovo sekcionirati tok podataka prilikom prebacivanja klju\u010deva na novi tip ili vrijednost. Ponekad se ponovo sekcioniranje izvr\u0161ava eksplicitno, a ponekad to Kafka Streams \u010dini automatski. Ponovno sekcioniranje je potrebno jer su se klju\u010devi promijenili i zapisi trebaju biti u novim sekcijama, ina\u010de spajanje ne\u0107e biti mogu\u0107e (to je raspravljano u poglavlju 4, u odjeljku \u201ePonovno sekcioniranje podataka\u201c pododjeljka 4.2.4).<\/p>\n<h3>Ponovno dijeljenje ima svoju cijenu<\/h3>\n<p>\nPonovno dijeljenje zahtijeva tro\u0161kove \u2014 dodatne tro\u0161kove resursa za stvaranje privremenih tema, \u010duvanje dupliciranih podataka u jo\u0161 jednoj temi; tako\u0111er zna\u010di pove\u0107anje ka\u0161njenja zbog pisanja i \u010ditanja iz te teme. \u0160tovi\u0161e, ako je potrebno izvr\u0161iti povezivanje po vi\u0161e aspekata ili dimenzija, potrebno je organizirati povezivanja u lancu, prikazati zapise s novim klju\u010devima i ponovo provesti proces ponovnog dijeljenja.<\/p>\n<h3>Povezivanje s manjim skupovima podataka<\/h3>\n<p>\nU nekim slu\u010dajevima, koli\u010dina referentnih podataka s kojima planiramo povezivanje je relativno mala, tako da se njihova potpuna kopija mo\u017ee smjestiti lokalno na svaki od \u010dvorova. Za takve situacije u Kafka Streams predvi\u0111ena je klasa GlobalKTable.<\/p>\n<p>Instancije GlobalKTable su jedinstvene jer aplikacija replicira sve podatke na svaki od \u010dvorova. A s obzirom da na svakom od \u010dvorova postoje svi podaci, nije potrebno dijeliti tok doga\u0111aja po klju\u010du referentnih podataka kako bi bio dostupan svim sekcijama. Pomo\u0107u objekata GlobalKTable mo\u017eemo tako\u0111er izvoditi bezklju\u010dna povezivanja. Vratimo se jednom od prethodnih primjera kako bismo demonstrirali ovu mogu\u0107nost.<\/p>\n<h3>Povezivanje objekata KStream s objektima GlobalKTable<\/h3>\n<p>\nU pododjeljku 5.3.2 izveli smo vremensko agregiranje burzovnih transakcija po kupcima. Rezultati ovog agregiranja izgledali su otprilike ovako:<\/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>\nIako su ti rezultati odgovarali postavljenoj cilju, bilo bi zgodnije kada bi se tako\u0111er ispisivao ime klijenta i puno ime kompanije. Kako bismo dodali ime kupca i naziv kompanije, mogli bismo izvesti uobi\u010dajena povezivanja, ali bi to zahtijevalo stvaranje dva prikaza klju\u010deva i ponovno dijeljenje. Pomo\u0107u GlobalKTable mo\u017eemo izbje\u0107i tro\u0161kove takvih operacija.<\/p>\n<p>Za to \u0107emo iskoristiti objekt countStream iz popisa 5.11 (odgovaraju\u0107i kod mo\u017ee se prona\u0107i u datoteci src\/main\/java\/bbejeck\/chapter_5\/GlobalKTableExample.java), povezuju\u0107i ga s dva objekta GlobalKTable.<\/p>\n<p><img decoding=\"async\" alt=\"Knjiga \u201eKafka Streams u akciji. Aplikacije i mikroslu\u017ebe za rad u stvarnom vremenu\u201c\" src=\"\/wp-content\/uploads\/fc4d91bbe062ceb94f5650224840b81e.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nVe\u0107 smo o tome razgovarali ranije, pa ne\u0107u ponavljati. Me\u0111utim, istaknuo bih da je kod u funkciji toStream().map radi bolje \u010ditljivosti apstrahiran u objekt-funkciju umjesto ugradbene lambda izraze.<\/p>\n<p>Sljede\u0107i korak je deklaracija dva primjerka GlobalKTable (prikazani kod mo\u017eete prona\u0107i u datoteci src\/main\/java\/bbejeck\/chapter_5\/GlobalKTableExample.java) (listanje 5.12).<\/p>\n<p><img decoding=\"async\" alt=\"Knjiga \u201eKafka Streams u akciji. Aplikacije i mikroslu\u017ebe za rad u stvarnom vremenu\u201c\" src=\"\/wp-content\/uploads\/db3918895f174c8cfb5fc927b55f87a1.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p>Obratite pa\u017enju da su nazivi tema opisani pomo\u0107u enumeracijskih tipova.<\/p>\n<p>Sada kada smo pripremili sve komponente, jo\u0161 je potrebno napisati kod za povezivanje (koji se mo\u017ee na\u0107i u datoteci src\/main\/java\/bbejeck\/chapter_5\/GlobalKTableExample.java) (listanje 5.13).<\/p>\n<p><img decoding=\"async\" alt=\"Knjiga \u201eKafka Streams u akciji. Aplikacije i mikroslu\u017ebe za rad u stvarnom vremenu\u201c\" src=\"\/wp-content\/uploads\/799360cc99f1920c190a61fd4685d4ff.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nIako ovaj kod sadr\u017ei dva povezivanja, organizirani su u obliku lanca, jer ni jedan od njihovih rezultata nije kori\u0161ten odvojeno. Rezultati se ispisuju na kraju cijele operacije.<\/p>\n<p>Kada pokrenete gornju operaciju povezivanja, dobit \u0107ete rezultate sljede\u0107eg tipa:<\/p>\n<pre><code class=\"plaintext\">{customer='Barney, Smith' company=\"Exxon\", transactions= 17}<\/code><\/pre>\n<p>\nSu\u0161tina se nije promijenila, ali ovi rezultati izgledaju razumljivije.<\/p>\n<p>Ako ra\u010dunamo poglavlje 4, ve\u0107 ste vidjeli nekoliko tipova povezivanja u akciji. Oni su navedeni u tablici 5.2. Ova tablica odra\u017eava mogu\u0107nosti povezivanja relevantne za verziju 1.0.0 Kafka Streams; u budu\u0107im izdanjima, mo\u017eda \u0107e se ne\u0161to promijeniti.<\/p>\n<p><img decoding=\"async\" alt=\"Knjiga \u201eKafka Streams u akciji. Aplikacije i mikroslu\u017ebe za rad u stvarnom vremenu\u201c\" src=\"\/wp-content\/uploads\/8e4cf35c64a8431bda43a5e748de275f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nZaklju\u010dno, podsjetit \u0107u na osnovno: mo\u017eete povezivati tokove doga\u0111aja (KStream) i tokove a\u017euriranja (KTable) pomo\u0107u lokalnog stanja. Osim toga, ako je veli\u010dina referentnih podataka malo, mo\u017eete iskoristiti objekt GlobalKTable. GlobalKTable replicira sve sekcije na svaki \u010dvor aplikacije Kafka Streams, osiguravaju\u0107i time dostupnost svih podataka bez obzira na to kojoj sekciji pripada klju\u010d.<\/p>\n<p>Dalje \u0107emo vidjeti mogu\u0107nost Kafka Streams koja omogu\u0107uje pra\u0107enje promjena stanja bez konzumiranja podataka iz Kafka teme.<\/p>\n<h3>5.3.5. Stanje dostupno za upite<\/h3>\n<p>\nVe\u0107 smo izvodili nekoliko operacija koje uklju\u010duju stanje i uvijek smo ispisivali rezultate na konzolu (za razvojne svrhe) ili ih snimali u temu (za industrijske svrhe). Prilikom snimanja rezultata u temu, potrebno je koristiti Kafka potro\u0161a\u010da za njihovo pregledavanje.<\/p>\n<p>\u010citanje podataka iz ovih tema mo\u017ee se smatrati vrstom materializiranih prikaza (materialized views). Za na\u0161e potrebe mo\u017ee se koristiti definicija materializiranog prikaza iz \"Wikipedije\": \u201e...fizi\u010dki objekt baze podataka koji sadr\u017ei rezultate izvr\u0161enja upita. Na primjer, mo\u017ee biti lokalna kopija udaljenih podataka, ili podskup redaka i\/ili stupaca tablice ili rezultata spajanja, ili sa\u017eeta tablica koja je dobijena agregiranjem\u201c (https:\/\/en.wikipedia.org\/wiki\/Materialized_view).<\/p>\n<p>Kafka Streams tako\u0111er omogu\u0107uje izvr\u0161avanje interaktivnih upita (interactive queries) na skladi\u0161tima stanja, \u0161to omogu\u0107uje izravno \u010ditanje ovih materializiranih prikaza. Va\u017eno je napomenuti da upit na skladi\u0161te stanja ima karakter operacije \u201esamo za \u010ditanje\u201c. Zahvaljuju\u0107i tome mo\u017eete biti sigurni da ne\u0107ete slu\u010dajno u\u010diniti stanje nesuglasnim tijekom obrade podataka aplikacijom.<\/p>\n<p>Mogu\u0107nost izravnih upita na skladi\u0161tima stanja ima veliku va\u017enost. To zna\u010di da se mogu stvarati aplikacije \u2014 informacijske plo\u010de bez potrebe da se prvo podaci dobivaju od potro\u0161a\u010da Kafke. Tako\u0111er pove\u0107ava u\u010dinkovitost aplikacije, jer nije potrebno ponovo zapisivati podatke:<\/p>\n<ul>\n<li>zbog lokalnosti podataka, na njih se mo\u017ee brzo pristupiti;<\/li>\n<li>isklju\u010duje se dupliciranje podataka, budu\u0107i da se oni ne zapisuju u vanjsko skladi\u0161te.<\/li>\n<\/ul>\n<p>\nNajva\u017enije \u0161to bih volio da zapamtite: mo\u017eete izravno izvr\u0161avati upite na stanju iz aplikacije. Ne mo\u017ee se precijeniti mogu\u0107nosti koje vam to pru\u017ea. Umjesto da konzumirate podatke iz Kafke i pohranjujete zapise u bazu podataka za aplikaciju, mo\u017eete izvr\u0161avati upite na skladi\u0161tima stanja s istim rezultatom. Izravni upiti na skladi\u0161tima stanja zna\u010de manji volumen koda (nedostatak potro\u0161a\u010da) i manje softverskog rje\u0161enja (nedostatak potrebe za tablicom baze podataka za pohranu rezultata).<\/p>\n<p>Obuhvatili smo zna\u010dajan volumen informacija u ovom poglavlju, stoga \u0107emo na trenutak prekinuti na\u0161u raspravu o interaktivnim upitima na skladi\u0161tima stanja. No, ne brinite: u poglavlju 9 stvorit \u0107emo jednostavnu aplikaciju \u2014 informacijski panel s interaktivnim upitima. Za demonstraciju interaktivnih upita i mogu\u0107nosti njihovog dodavanja u aplikacije Kafka Streams koristit \u0107emo neke od primjera iz ovog i prethodnog poglavlja.<\/p>\n<h3>Sa\u017eetak<\/h3>\n<p><\/p>\n<ul>\n<li>KStream objekti predstavljaju tokove doga\u0111aja, sli\u010dne upisima u bazu podataka. KTable objekti predstavljaju tokove a\u017euriranja, vi\u0161e su sli\u010dni a\u017euriranjima u bazi podataka. Veli\u010dina KTable objekta ne raste, stari unosi se zamjenjuju novima.<\/li>\n<li>KTable objekti su nu\u017eni za operacije agregacije.<\/li>\n<li>Pomo\u0107u operacija prozora mogu\u0107e je razdvojiti agregirane podatke prema vremenskim ko\u0161aricama.<\/li>\n<li>Uz GlobalKTable objekte mo\u017eete pristupiti referentnim podacima s bilo kojeg mjesta unutar aplikacije, bez obzira na podjelu po sekcijama.<\/li>\n<li>Mogu\u0107e su me\u0111usobne veze izme\u0111u KStream, KTable i GlobalKTable objekata.<\/li>\n<\/ul>\n<p>\nDo sada smo se fokusirali na izradu aplikacija Kafka Streams pomo\u0107u visokorazinskog DSL KStream. Iako visokorazinski pristup omogu\u0107ava stvaranje urednih i sa\u017eetih programa, njegovo kori\u0161tenje predstavlja odre\u0111eni kompromis. Rad s DSL KStream zna\u010di pove\u0107anu sa\u017eetost koda na ra\u010dun smanjenja kontrole. U sljede\u0107em poglavlju razmotrit \u0107emo niskorazinski API \u010dvorova-obraditelja i isprobati druge kompromise. Programi \u0107e biti du\u017ei nego \u0161to su bili do sada, ali \u0107emo imati mogu\u0107nost stvaranja gotovo bilo kojeg \u010dvora-obraditelja koji nam mo\u017ee zatrebati.<\/p>\n<p>\u2192 Vi\u0161e detalja o knjizi mo\u017eete prona\u0107i na <noindex><a rel=\"nofollow\" href=\"https:\/\/www.piter.com\/collection\/best\/product\/kafka-streams-v-deystvii-prilozheniya-i-mikroservisy-dlya-raboty-v-realnom-vremeni\">web stranici izdava\u010da<\/a><\/noindex><\/p>\n<p>\u2192 Za Habr\u017eitelje popust od 25% putem kupona \u2014 <b>Kafka Streams<\/b><\/p>\n<p>\u2192 Nakon pla\u0107anja fizi\u010dke verzije knjige, elektronska knjiga se \u0161alje na e-mail.<br \/>\n<br \/>Izvor: <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\/hr\/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=\"hr_HR\" \/>\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\/hr\/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\udd47Knjiga \u201eKafka Streams u akciji. Aplikacije i mikroservisi za rad u stvarnom vremenu\u201d | ProHoster","description":"","canonical_url":"https:\/\/prohoster.info\/hr\/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":"hr_HR","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\/hr\/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\/hr\/wp-json\/wp\/v2\/posts\/35786","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/comments?post=35786"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/posts\/35786\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/media?parent=35786"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/categories?post=35786"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/tags?post=35786"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}