{"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\/it\/blog\/administrirovanie\/kniga-kafka-streams-v-dejstvii-prilozheniya-i-mikroservisy-dlya-raboty-v-realnom-vremeni","title":{"rendered":"Libro \u00abKafka Streams in azione. Applicazioni e microservizi per il lavoro in tempo reale\u00bb","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=\"Libro \u00abKafka Streams in azione. Applicazioni e microservizi per il lavoro in tempo reale\u00bb\" src=\"\/wp-content\/uploads\/6f8bd2b31b87b0c760c1148515893c43.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex> Ciao, Habrozhiteli! Questo libro \u00e8 adatto a qualsiasi sviluppatore che desidera comprendere l'elaborazione dei flussi. Capire la programmazione distribuita aiuter\u00e0 a studiare meglio Kafka e Kafka Streams. Sarebbe utile conoscere anche il framework Kafka, ma non \u00e8 obbligatorio: vi racconter\u00f2 tutto ci\u00f2 che serve. Gli sviluppatori esperti di Kafka, cos\u00ec come i neofiti, grazie a questo libro apprenderanno come creare interessanti applicazioni per l'elaborazione dei flussi utilizzando la libreria Kafka Streams. Gli sviluppatori Java di livello medio e alto, gi\u00e0 familiari con concetti come la serializzazione, impareranno ad applicare le proprie competenze per creare applicazioni Kafka Streams. Il codice sorgente del libro \u00e8 scritto in Java 8 e utilizza ampiamente la sintassi delle espressioni lambda di Java 8, quindi la capacit\u00e0 di lavorare con le funzioni lambda (anche in un altro linguaggio di programmazione) sar\u00e0 utile.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h3>Estratto. 5.3. Operazioni di aggregazione e finestre<\/h3>\n<p>\nIn questo capitolo passeremo a esplorare le parti pi\u00f9 promettenti di Kafka Streams. Fino a questo momento abbiamo esaminato i seguenti aspetti di Kafka Streams:<\/p>\n<ul>\n<li>creazione della topologia di elaborazione;<\/li>\n<li>utilizzo dello stato nelle applicazioni in streaming;<\/li>\n<li>esecuzione di connessioni di flussi di dati;<\/li>\n<li>differenze tra flussi di eventi (KStream) e flussi di aggiornamenti (KTable).<\/li>\n<\/ul>\n<p>\nNei seguenti esempi mettere insieme tutti questi elementi. Inoltre, vi presenteremo le operazioni a finestra, un'altra straordinaria funzionalit\u00e0 delle applicazioni in streaming. Il nostro primo esempio riguarder\u00e0 una semplice aggregazione.<\/p>\n<h3>5.3.1. Aggregazione del volume delle vendite delle azioni per settori industriali<\/h3>\n<p>\nL'aggregazione e la raggruppamento sono strumenti vitali quando si lavora con dati in streaming. Esaminare singoli record man mano che arrivano spesso si rivela insufficiente. Per estrarre informazioni aggiuntive dai dati \u00e8 necessaria la loro aggregazione e combinazione.<\/p>\n<p>In questo esempio dovrete indossare il costume di un trader intraday, che deve monitorare i volumi delle vendite delle azioni di societ\u00e0 in vari settori industriali. In particolare, vi interessano cinque societ\u00e0 con i maggiori volumi di vendita di azioni in ciascun settore.<\/p>\n<p>Per ottenere un simile aggregato, saranno necessari diversi passaggi per convertire i dati nella forma desiderata (parlando in termini generali).<\/p>\n<ol>\n<li>Creare una fonte basata su un argomento che pubblichi informazioni grezze sul trading di azioni. Dobbiamo mappare un oggetto di tipo StockTransaction in un oggetto di tipo ShareVolume. Il fatto \u00e8 che l'oggetto StockTransaction contiene metadati sulle vendite, mentre noi abbiamo bisogno solo dei dati relativi al numero di azioni vendute.<\/li>\n<li>Raggruppare i dati ShareVolume per simboli azionari. Dopo aver raggruppato per simboli, \u00e8 possibile comprimere questi dati in somme intermedie dei volumi di vendita delle azioni. \u00c8 importante notare che il metodo KStream.groupBy restituisce un'istanza di tipo KGroupedStream. Per ottenere un'istanza di KTable, \u00e8 possibile chiamare successivamente il metodo KGroupedStream.reduce.<\/li>\n<\/ol>\n<p><\/p>\n<blockquote><p><b>Cos'\u00e8 l'interfaccia KGroupedStream<\/b><\/p>\n<p>I metodi KStream.groupBy e KStream.groupByKey restituiscono un'istanza di KGroupedStream. KGroupedStream rappresenta in modo intermedio un flusso di eventi dopo la raggruppamento per chiavi. Non \u00e8 destinato ad essere utilizzato direttamente. Invece, KGroupedStream \u00e8 utilizzato per operazioni di aggregazione, il cui risultato \u00e8 sempre un KTable. E poich\u00e9 le operazioni di aggregazione producono un KTable e utilizzano uno store di stato, \u00e8 possibile che non tutti gli aggiornamenti vengano inviati ulteriormente attraverso la pipeline.<\/p>\n<p>Il metodo KTable.groupBy restituisce un KGroupedTable simile, un rappresentazione intermedia di un flusso di aggiornamenti raggruppati per chiave.<\/p><\/blockquote>\n<p>\nFacciamo una breve pausa e osserviamo la figura 5.9, in cui \u00e8 mostrato cosa abbiamo ottenuto. Questa topologia dovrebbe esserti gi\u00e0 familiare.<\/p>\n<p><img decoding=\"async\" alt=\"Libro \u00abKafka Streams in azione. Applicazioni e microservizi per il lavoro in tempo reale\u00bb\" src=\"\/wp-content\/uploads\/9fd61317cde376362adcaeec72908919.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDiamo un'occhiata al codice per questa topologia (si trova nel file src\/main\/java\/bbejeck\/chapter_5\/AggregationsAndReducingExample.java) (elenco 5.2).<\/p>\n<p><img decoding=\"async\" alt=\"Libro \u00abKafka Streams in azione. Applicazioni e microservizi per il lavoro in tempo reale\u00bb\" src=\"\/wp-content\/uploads\/f937287e448295fbd467c283ceca316a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nIl codice fornito si distingue per la sua brevit\u00e0 e per l'ampio numero di operazioni eseguite in poche righe. Nel primo parametro del metodo builder.stream puoi notare qualcosa di nuovo per te: il valore dell'enumerazione AutoOffsetReset.EARLIEST (esiste anche LATEST), impostato tramite il metodo Consumed.withOffsetResetPolicy. Utilizzando questo tipo enumerativo, puoi specificare la strategia di reset degli offset per ogni KStream o KTable, che ha priorit\u00e0 sul parametro di reset degli offset nella configurazione.<\/p>\n<blockquote><p><b>GroupByKey e GroupBy<\/b><\/p>\n<p>Nell'interfaccia KStream ci sono due metodi per raggruppare le registrazioni: GroupByKey e GroupBy. Entrambi restituiscono un KGroupedTable, quindi potrebbe sorgere un legittimo quesito: qual \u00e8 la differenza tra di loro e quando utilizzare l'uno o l'altro?<\/p>\n<p>Il metodo GroupByKey si applica quando le chiavi nel KStream sono gi\u00e0 non vuote. Inoltre, il flag 'richiesta di ri-partizionamento' non \u00e8 mai stato impostato.<\/p>\n<p>Il metodo GroupBy presuppone che tu abbia modificato le chiavi per la raggruppamento, quindi il flag di ri-partizionamento \u00e8 impostato su true. L'esecuzione dopo il metodo GroupBy di join, aggregazioni, ecc. comporter\u00e0 un ri-partizionamento automatico.<br \/>\nRiassunto: si dovrebbe usare GroupByKey ogni volta che \u00e8 possibile, invece di GroupBy.<\/p><\/blockquote>\n<p>\nCosa fanno i metodi mapValues e groupBy \u00e8 chiaro, quindi diamo un'occhiata al metodo sum() (che si trova nel file src\/main\/java\/bbejeck\/model\/ShareVolume.java) (listing 5.3).<\/p>\n<p><img decoding=\"async\" alt=\"Libro \u00abKafka Streams in azione. Applicazioni e microservizi per il lavoro in tempo reale\u00bb\" src=\"\/wp-content\/uploads\/8e9a6f873594f9b5fef9a96c42353a61.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nIl metodo ShareVolume.sum restituisce la somma intermedia del volume delle azioni, e il risultato dell'intera catena di calcoli rappresenta un oggetto KTable. Ora capite il ruolo di KTable. Quando gli oggetti ShareVolume arrivano, l'ultima aggiornamento rilevante viene mantenuto nell'oggetto KTable corrispondente. \u00c8 importante non dimenticare che tutti gli aggiornamenti sono riflessi nel precedente shareVolumeKTable, ma non tutti vengono inoltrati ulteriormente.<\/p>\n<p>Successivamente, utilizziamo questo KTable per aggregare (in base al numero di azioni vendute) per ottenere cinque aziende con i maggiori volumi di vendita di azioni in ciascun settore industriale. Le nostre azioni saranno simili a quelle della prima aggregazione.<\/p>\n<ol>\n<li>Eseguire un'altra operazione di groupBy per raggruppare i singoli oggetti ShareVolume in base ai settori industriali.<\/li>\n<li>Iniziare a sommare gli oggetti ShareVolume. Questa volta, l'oggetto di aggregazione \u00e8 una coda a priorit\u00e0 di dimensione fissa. In questa coda di dimensione fissa vengono mantenute solo cinque aziende con le maggiori quantit\u00e0 di azioni vendute.<\/li>\n<li>Mostrare le code dal punto precedente come valore stringa e restituire le cinque pi\u00f9 vendute per numero di azioni suddivise per settori industriali.<\/li>\n<li>Registrare i risultati in forma di stringa nel topic.<\/li>\n<\/ol>\n<p>\nNella figura 5.10 \u00e8 mostrato il grafo della topologia del flusso dei dati. Come potete vedere, il secondo cerchio di elaborazione \u00e8 piuttosto semplice.<\/p>\n<p><img decoding=\"async\" alt=\"Libro \u00abKafka Streams in azione. Applicazioni e microservizi per il lavoro in tempo reale\u00bb\" src=\"\/wp-content\/uploads\/dabd1507eee267038edb7f8d76d8d8ae.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nOra che avete chiaramente compreso la struttura di questo secondo cerchio di elaborazione, potete rivolgervi al suo codice sorgente (lo troverete nel file src\/main\/java\/bbejeck\/chapter_5\/AggregationsAndReducingExample.java) (elenco 5.4).<\/p>\n<p>In questo inizializzatore c'\u00e8 una variabile fixedQueue. Questo \u00e8 un oggetto utente - un adattatore per java.util.TreeSet, utilizzato per tenere traccia dei N migliori risultati in ordine decrescente della quantit\u00e0 di azioni vendute.<\/p>\n<p><img decoding=\"async\" alt=\"Libro \u00abKafka Streams in azione. Applicazioni e microservizi per il lavoro in tempo reale\u00bb\" src=\"\/wp-content\/uploads\/488b072b0d91b81c925ca72291e69e48.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nHai gi\u00e0 incontrato le sfide di groupBy e mapValues, quindi non ci fermeremo su di esse (chiamiamo il metodo KTable.toStream, poich\u00e9 il metodo KTable.print \u00e8 considerato obsoleto). Ma non hai ancora visto la versione KTable del metodo aggregate(), quindi dedicheremo un po' di tempo alla sua discussione.<\/p>\n<p>Come ricordi, la caratteristica di KTable \u00e8 che le registrazioni con la stessa chiave sono considerate aggiornamenti. KTable sostituisce la vecchia registrazione con la nuova. L'aggregazione avviene in modo simile: vengono aggregate le ultime registrazioni con una stessa chiave. Quando un record arriva, viene aggiunto all'istanza della classe FixedSizePriorityQueue tramite un sommatorie (il secondo parametro nella chiamata del metodo aggregate), ma se esiste gi\u00e0 un'altra registrazione con la stessa chiave, la vecchia registrazione viene rimossa tramite un sottrattore (il terzo parametro nella chiamata del metodo aggregate).<\/p>\n<p>Questo significa che il nostro aggregatore, FixedSizePriorityQueue, non aggrega tutti i valori con una chiave unica, ma conserva la somma mobile delle quantit\u00e0 delle N azioni pi\u00f9 vendute. In ogni record in arrivo \u00e8 contenuto il numero totale di azioni vendute fino a quel momento. KTable ti fornir\u00e0 informazioni su quali azioni di quale azienda sono attualmente le pi\u00f9 vendute, non \u00e8 necessaria un'aggregazione mobile di ogni aggiornamento.<\/p>\n<p>Abbiamo imparato a fare due cose importanti:<\/p>\n<ul>\n<li>raggruppare i valori in KTable per una chiave comune;<\/li>\n<li>eseguire su questi valori raggruppati operazioni utili come la riduzione e l'aggregazione.<\/li>\n<\/ul>\n<p>\nEssere in grado di eseguire queste operazioni \u00e8 fondamentale per comprendere il significato dei dati che si muovono attraverso l'applicazione Kafka Streams e scoprire quali informazioni portano.<\/p>\n<p>Abbiamo anche riunito alcuni dei concetti chiave discussi in precedenza in questo libro. Nel capitolo 4 abbiamo parlato dell'importanza dello stato locale a prova di guasto per le applicazioni in streaming. Il primo esempio di questo capitolo ha dimostrato perch\u00e9 lo stato locale sia cos\u00ec fondamentale: consente di tenere traccia delle informazioni che hai gi\u00e0 visualizzato. L'accesso locale evita ritardi di rete, rendendo l'applicazione pi\u00f9 performante e resistente agli errori.<\/p>\n<p>Quando si esegue qualsiasi operazione di aggregazione o riduzione, \u00e8 necessario specificare il nome dello stato di archiviazione. Le operazioni di aggregazione e riduzione restituiscono un'istanza di KTable, mentre KTable utilizza lo stato di archiviazione per sostituire i vecchi risultati con i nuovi. Come hai visto, non tutti gli aggiornamenti vengono inviati ulteriormente nel pipeline, e questo \u00e8 importante, poich\u00e9 le operazioni di aggregazione sono progettate per fornire informazioni finali. Se non si utilizza lo stato locale, KTable invier\u00e0 ulteriormente tutti i risultati di aggregazione e riduzione.<\/p>\n<p>In seguito, analizzeremo l'esecuzione di operazioni come l'aggregazione all'interno di un intervallo di tempo specifico \u2014 le cosiddette operazioni a finestra (windowing operations).<\/p>\n<h3>5.3.2. Operazioni a finestra<\/h3>\n<p>\nNella sezione precedente abbiamo introdotto la convoluzione e l'aggregazione 'mobile'. L'applicazione ha effettuato una convoluzione continua del volume delle vendite delle azioni seguita dall'aggregazione delle cinque azioni pi\u00f9 vendute in borsa.<\/p>\n<p>A volte, tali aggregazioni e convoluzioni continue sono necessarie. Altre volte, \u00e8 necessario eseguire operazioni solo su un intervallo di tempo specifico. Ad esempio, calcolare quante operazioni di borsa sono state effettuate su un'azione di una particolare azienda negli ultimi 10 minuti. Oppure quanti utenti hanno cliccato su un nuovo banner pubblicitario negli ultimi 15 minuti. L'applicazione pu\u00f2 eseguire tali operazioni pi\u00f9 volte, ma con risultati relativi solo agli intervalli di tempo specificati (finestre temporali).<\/p>\n<h3>Conteggio delle transazioni di borsa per acquirente<\/h3>\n<p>\nNel seguente esempio, ci occuperemo del monitoraggio delle transazioni di borsa tra diversi trader\u2014sia grandi aziende che astuti finanzieri solitari.<\/p>\n<p>Ci sono due possibili motivi per tale monitoraggio. Uno \u00e8 la necessit\u00e0 di sapere cosa acquistano\/vendono i leader di mercato. Se questi grandi attori e investitori esperti vedono delle opportunit\u00e0, ha senso seguire la loro strategia. Il secondo motivo \u00e8 il desiderio di notare eventuali segni di negoziazioni illecite che utilizzano informazioni riservate. Per fare ci\u00f2, \u00e8 necessario analizzare la correlazione tra grandi picchi di vendite e importanti comunicati stampa.<\/p>\n<p>Questo monitoraggio \u00e8 composto da fasi quali:<\/p>\n<ul>\n<li>creazione di un flusso di lettura dal topic stock-transactions;<\/li>\n<li>raggruppamento delle registrazioni in ingresso per identificativo del compratore e simbolo del titolo azionario. La chiamata al metodo groupBy restituisce un'istanza della classe KGroupedStream;<\/li>\n<li>Il ritorno tramite il metodo KGroupedStream.windowedBy del flusso di dati limitato da una finestra temporale, che consente di eseguire aggregazioni a finestra. A seconda del tipo di finestra, viene restituito un TimeWindowedKStream o un SessionWindowedKStream;<\/li>\n<li>il conteggio delle transazioni per l'operazione di aggregazione. Il flusso di dati a finestra determina se un particolare record viene incluso in questo conteggio;<\/li>\n<li>la registrazione dei risultati in un topic o la loro visualizzazione nella console durante lo sviluppo.<\/li>\n<\/ul>\n<p>\nLa topologia di questa applicazione \u00e8 semplice, ma un'immagine esplicativa non guasterebbe. Diamo un'occhiata alla fig. 5.11.<\/p>\n<p>In seguito, esamineremo la funzionalit\u00e0 delle operazioni a finestra e il codice corrispondente.<\/p>\n<p><img decoding=\"async\" alt=\"Libro \u00abKafka Streams in azione. Applicazioni e microservizi per il lavoro in tempo reale\u00bb\" src=\"\/wp-content\/uploads\/67d9d8d8acb1370a7c7fe5cd9a8b6aa7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h3>Tipi di finestre<\/h3>\n<p>\nIn Kafka Streams ci sono tre tipi di finestre:<\/p>\n<ul>\n<li>finestra di sessione;<\/li>\n<li>finestra a scorrimento (tumbling);<\/li>\n<li>finestra mobile \/ a scatti (sliding \/ hopping).<\/li>\n<\/ul>\n<p>\nLa scelta dipende dalle esigenze aziendali. Le finestre \"rimbalzanti\" e \"saltellanti\" sono limitate nel tempo, mentre i limiti delle finestre di sessione sono legati alle azioni degli utenti: la durata della sessione \u00e8 determinata esclusivamente da quanto attivamente si comporta l'utente. \u00c8 importante ricordare che tutti i tipi di finestre si basano su etichette di data\/ora dei registri, non sull'ora di sistema.<\/p>\n<p>Successivamente, realizzeremo la nostra topologia con ciascun tipo di finestra. Il codice completo verr\u00e0 fornito solo nel primo esempio; per gli altri tipi di finestra, non ci sar\u00e0 nulla da cambiare, tranne il tipo di operazione della finestra.<\/p>\n<h3>Finestre di sessione<\/h3>\n<p>\nLe finestre di sessione differiscono notevolmente da tutti gli altri tipi di finestre. Sono limitate non tanto dal tempo quanto dall'attivit\u00e0 dell'utente (o dall'attivit\u00e0 dell'entit\u00e0 che si desidera monitorare). Le finestre di sessione sono delimitate da periodi di inattivit\u00e0.<\/p>\n<p>La figura 5.12 illustra il concetto di finestre di sessione. Una sessione pi\u00f9 piccola si fonder\u00e0 con la sessione a sinistra. Una sessione a destra sar\u00e0 separata, in quanto segue un lungo periodo di inattivit\u00e0. Le finestre di sessione si basano sulle azioni degli utenti, ma utilizzano timestamp dai registri per determinare a quale sessione si riferisce la registrazione.<\/p>\n<p><img decoding=\"async\" alt=\"Libro \u00abKafka Streams in azione. Applicazioni e microservizi per il lavoro in tempo reale\u00bb\" src=\"\/wp-content\/uploads\/d39a5db7af7d6aa2194802622b2b47fd.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h3>Utilizzo delle finestre di sessione per il monitoraggio delle transazioni di borsa<\/h3>\n<p>\nUtilizziamo le finestre di sessione per catturare informazioni sulle transazioni di borsa. L'implementazione delle finestre di sessione \u00e8 mostrata nel listing 5.5 (che si trova nel file src\/main\/java\/bbejeck\/chapter_5\/CountingWindowingAndKTableJoinExample.java).<\/p>\n<p><img decoding=\"async\" alt=\"Libro \u00abKafka Streams in azione. Applicazioni e microservizi per il lavoro in tempo reale\u00bb\" src=\"\/wp-content\/uploads\/2dcbd9a36baec0e746aad165121451b3.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nLa maggior parte delle operazioni di questa topologia le avete gi\u00e0 incontrate, quindi non c'\u00e8 bisogno di rivederle qui. Ma ci sono anche alcuni nuovi elementi che discuteremo ora.<\/p>\n<p>In ogni operazione groupBy, di solito viene eseguita qualche operazione di aggregazione (aggregazione, riduzione o conteggio). Si pu\u00f2 eseguire un'aggregazione cumulativa con un risultato progressivo, o un'aggregazione a finestra, in cui vengono considerati i registri all'interno di una finestra temporale specificata.<\/p>\n<p>Il codice dell'elenco 5.5 conta il numero di transazioni all'interno delle finestre di sessione. Nella figura 5.13 queste azioni vengono analizzate passo dopo passo.<\/p>\n<p>Con la chiamata windowedBy(SessionWindows.with(twentySeconds).until(fifteenMinutes)) creiamo una finestra di sessione con un intervallo di inattivit\u00e0 di 20 secondi e un intervallo di conservazione di 15 minuti. Un intervallo di inattivit\u00e0 di 20 secondi significa che l'applicazione includer\u00e0 qualsiasi registrazione che arriver\u00e0 entro 20 secondi dalla fine o dall'inizio della sessione corrente nella sessione attiva.<\/p>\n<p><img decoding=\"async\" alt=\"Libro \u00abKafka Streams in azione. Applicazioni e microservizi per il lavoro in tempo reale\u00bb\" src=\"\/wp-content\/uploads\/9bd47b04698086872fd135b4c67eb938.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nSuccessivamente indichiamo quale operazione di aggregazione deve essere eseguita nella finestra di sessione \u2014 in questo caso count. Se la registrazione in ingresso esce oltre l'intervallo di inattivit\u00e0 (da ciascun lato del timestamp), l'applicazione crea una nuova sessione. L'intervallo di conservazione significa mantenere la sessione per un certo periodo e consente dati tardivi che superano il periodo di inattivit\u00e0 della sessione, ma che possono ancora essere uniti. Inoltre, l'inizio e la fine della nuova sessione, risultante dalla fusione, corrispondono al timestamp pi\u00f9 presto e a quello pi\u00f9 recente.<\/p>\n<p>Esaminiamo alcune voci del metodo count per vedere come funzionano le sessioni (tab. 5.1).<\/p>\n<p><img decoding=\"async\" alt=\"Libro \u00abKafka Streams in azione. Applicazioni e microservizi per il lavoro in tempo reale\u00bb\" src=\"\/wp-content\/uploads\/ec04aae466d88c2d2349474069c8d541.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nQuando arrivano le voci, cerchiamo sessioni gi\u00e0 esistenti con la stessa chiave, un orario di fine precedente all'attuale timestamp e un orario di inizio successivo all'attuale timestamp + intervallo di inattivit\u00e0. Tenendo conto di ci\u00f2, quattro voci della tab. 5.1 si uniscono in un'unica sessione nel modo seguente.<\/p>\n<p>1. La prima voce \u00e8 la 1, quindi l'orario di inizio \u00e8 uguale all'orario di fine ed \u00e8 00:00:00.<\/p>\n<p>2. Successivamente arriva la voce 2 e cerchiamo sessioni che finiscono non prima delle 23:59:55 e iniziano non oltre le 00:00:35. Troviamo la voce 1 e uniamo le sessioni 1 e 2. Prendiamo l'orario di inizio della sessione 1 (pi\u00f9 precedente) e l'orario di fine della sessione 2 (pi\u00f9 tardivo), cos\u00ec la nostra nuova sessione inizia alle 00:00:00 e termina alle 00:00:15.<\/p>\n<p>3. Arriva la voce 3, cerchiamo sessioni tra le 00:00:30 e le 00:01:10 e non troviamo alcuna. Aggiungiamo la seconda sessione per la chiave 123-345-654,FFBE, che inizia e finisce alle 00:00:50.<\/p>\n<p>4. Arriva la registrazione 4 e cerchiamo sessioni tra le 23:59:45 e le 00:00:25. Questa volta sono presenti entrambe le sessioni \u2014 1 e 2. Tutte e tre le sessioni vengono unite in una sola, con l'orario di inizio alle 00:00:00 e l'orario di fine alle 00:00:15.<\/p>\n<p>Dalla narrazione in questa sezione, \u00e8 importante ricordare i seguenti dettagli:<\/p>\n<ul>\n<li>le sessioni non sono finestre di dimensioni fisse. La durata di una sessione \u00e8 determinata dall'attivit\u00e0 all'interno di un determinato intervallo temporale;<\/li>\n<li>i timestamp nei dati determinano se un evento rientra in una sessione esistente o in un intervallo di inattivit\u00e0.<\/li>\n<\/ul>\n<p>\nDiscuteremo ora il prossimo tipo di finestre \u2014 le finestre 'tumbling'.<\/p>\n<h3>Finestre 'tumbling'<\/h3>\n<p>\nLe finestre 'tumbling' catturano eventi che rientrano in un determinato intervallo di tempo. Immaginate di dover catturare tutte le transazioni di borsa di un'azienda ogni 20 secondi, quindi raccogliete tutti gli eventi in quel periodo. Al termine dell'intervallo di 20 secondi, la finestra 'tumbling' si sposta e passa a un nuovo intervallo di osservazione di 20 secondi. La figura 5.14 illustra questa situazione.<\/p>\n<p><img decoding=\"async\" alt=\"Libro \u00abKafka Streams in azione. Applicazioni e microservizi per il lavoro in tempo reale\u00bb\" src=\"\/wp-content\/uploads\/e90e560d9ddda5e2e524b7c387ad9874.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nCome potete vedere, tutti gli eventi verificatisi negli ultimi 20 secondi sono inclusi nella finestra. Al termine di questo intervallo di tempo viene creata una nuova finestra.<\/p>\n<p>Nel listing 5.6 \u00e8 mostrato il codice che dimostra l'uso delle finestre 'cascading' per catturare ogni 20 secondi le transazioni di borsa (lo potete trovare nel file src\/main\/java\/bbejeck\/chapter_5\/CountingWindowingAndKtableJoinExample.java).<\/p>\n<p><img decoding=\"async\" alt=\"Libro \u00abKafka Streams in azione. Applicazioni e microservizi per il lavoro in tempo reale\u00bb\" src=\"\/wp-content\/uploads\/e055bb1b288c7d500b64372fe3fbf064.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nGrazie a questa piccola modifica alla chiamata del metodo TimeWindows.of, \u00e8 possibile utilizzare una finestra 'cascading'. In questo esempio non c'\u00e8 la chiamata al metodo until(), pertanto verr\u00e0 utilizzato l'intervallo di salvataggio predefinito, pari a 24 ore.<\/p>\n<p>Infine, \u00e8 tempo di passare all'ultimo tipo di finestre \u2014 le finestre 'hopping'.<\/p>\n<h3>Finestre scorrevoli ('hopping')<\/h3>\n<p>\nLe finestre scorrevoli\/'hopping' (sliding\/hopping) sono simili a quelle 'cascading', ma con una piccola differenza. Le finestre scorrevoli non aspettano la fine dell'intervallo di tempo prima di creare una nuova finestra per elaborare eventi recenti. Avviano nuovi calcoli dopo un intervallo di attesa, inferiore alla durata della finestra.<\/p>\n<p>Per illustrare le differenze tra le finestre \"sliding\" e \"tumbling\", torniamo all'esempio del conteggio delle transazioni di borsa. Il nostro obiettivo \u00e8 ancora contare il numero di transazioni, ma non vogliamo aspettare l'intero intervallo di tempo prima di aggiornare il contatore. Invece, aggiorneremo il contatore a intervalli di tempo pi\u00f9 brevi. Ad esempio, continueremo a contare il numero di transazioni ogni 20 secondi, ma aggiorneremo il contatore ogni 5 secondi, come mostrato nella figura 5.15. Cos\u00ec avremo tre finestre di risultati con dati sovrapposti.<\/p>\n<p><img decoding=\"async\" alt=\"Libro \u00abKafka Streams in azione. Applicazioni e microservizi per il lavoro in tempo reale\u00bb\" src=\"\/wp-content\/uploads\/415c8cd9f2b60d453a1a01c3bc99331f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nNella listing 5.7 \u00e8 fornito il codice per impostare finestre scorrevoli (che si pu\u00f2 trovare nel file src\/main\/java\/bbejeck\/chapter_5\/CountingWindowingAndKtableJoinExample.java).<\/p>\n<p><img decoding=\"async\" alt=\"Libro \u00abKafka Streams in azione. Applicazioni e microservizi per il lavoro in tempo reale\u00bb\" src=\"\/wp-content\/uploads\/ab2d1a64380d256d3fb084e16597417c.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nUna finestra \"tumbling\" pu\u00f2 essere trasformata in una \"sliding\" mediante l'aggiunta della chiamata al metodo advanceBy(). Nell'esempio fornito, l'intervallo di conservazione \u00e8 di 15 minuti.<\/p>\n<p>In questa sezione hai visto come limitare i risultati dell'aggregazione con finestre temporali. In particolare, vorremmo che tu ricordassi tre cose da questa sezione:<\/p>\n<ul>\n<li>la dimensione delle finestre di sessione \u00e8 limitata non dal lasso di tempo, ma dall'attivit\u00e0 degli utenti;<\/li>\n<li>le finestre 'saltellanti' forniscono un'idea degli eventi all'interno di un determinato intervallo di tempo;<\/li>\n<li>la durata di funzionamento delle finestre 'saltellanti' \u00e8 fissata, ma vengono aggiornate frequentemente e possono contenere in tutte le finestre registrazioni sovrapposte.<\/li>\n<\/ul>\n<p>\nIn seguito scopriremo come convertire KTable di nuovo in KStream per effettuare il join.<\/p>\n<h3>5.3.3. Unione di oggetti KStream e KTable<\/h3>\n<p>\nNel capitolo 4 abbiamo discusso dell'unione di due oggetti KStream. Ora dobbiamo imparare a unire KTable e KStream. Questo pu\u00f2 essere necessario per la seguente semplice ragione. KStream \u00e8 un flusso di registrazioni, mentre KTable \u00e8 un flusso di aggiornamenti delle registrazioni, ma a volte potrebbe essere necessario aggiungere un contesto aggiuntivo al flusso di registrazioni utilizzando aggiornamenti provenienti da KTable.<\/p>\n<p>Prendiamo i dati sul numero di transazioni di borsa e li uniamo alle notizie di borsa per le relative industrie. Ecco cosa occorre fare per raggiungere questo obiettivo tenendo conto del codice gi\u00e0 esistente.<\/p>\n<ol>\n<li>Convert the KTable object with data on the number of stock transactions into a KStream, replacing the key with one that represents the industry corresponding to the stock symbol.<\/li>\n<li>Create a KTable object that reads data from the stock news topic. This new KTable will be categorized by industries.<\/li>\n<li>Combine news updates with information about the number of stock transactions by industry.<\/li>\n<\/ol>\n<p>\nNow let's see how to implement this action plan.<\/p>\n<h3>Transforming KTable into KStream<\/h3>\n<p>\nTo convert KTable into KStream, you need to do the following.<\/p>\n<ol>\n<li>Invoke the KTable.toStream() method.<\/li>\n<li>Use the KStream.map method to 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 chain these operations as follows (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=\"Libro \u00abKafka Streams in azione. Applicazioni e microservizi per il lavoro in tempo reale\u00bb\" src=\"\/wp-content\/uploads\/0d43c2650f6e66e2816ed383da3a29c2.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nSince we are performing the KStream.map operation, the re-partitioning for the returned KStream instance is done automatically when it is used in the join.<\/p>\n<p>Abbiamo completato il processo di conversione; ora dobbiamo creare un oggetto KTable per leggere le notizie di borsa.<\/p>\n<h3>Creazione di KTable per le notizie di borsa<\/h3>\n<p>\nFortunatamente, per creare un oggetto KTable \u00e8 sufficiente una sola riga di codice (questo codice si trova nel file src\/main\/java\/bbejeck\/chapter_5\/CountingWindowingAndKtableJoinExample.java) (listing 5.9).<\/p>\n<p><img decoding=\"async\" alt=\"Libro \u00abKafka Streams in azione. Applicazioni e microservizi per il lavoro in tempo reale\u00bb\" src=\"\/wp-content\/uploads\/6e83a393fdc9ab74fda4cbdddddb5213.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n\u00c8 importante notare che non \u00e8 necessario specificare alcun oggetto Serde, poich\u00e9 nelle impostazioni vengono utilizzati Serde di tipo stringa. Inoltre, grazie all'uso dell'enumerazione EARLIEST, la tabella viene riempita con i registri fin dall'inizio.<\/p>\n<p>Ora possiamo passare all'ultimo passaggio: la connessione.<\/p>\n<h3>Connessione degli aggiornamenti delle notizie con i dati sul numero di transazioni<\/h3>\n<p>\nCreare la connessione non \u00e8 complicato. Utilizzeremo una connessione sinistra nel caso in cui non ci siano notizie di borsa per l'industria corrispondente (il codice necessario si trova nel file src\/main\/java\/bbejeck\/chapter_5\/CountingWindowingAndKtableJoinExample.java) (listing 5.10).<\/p>\n<p><img decoding=\"async\" alt=\"Libro \u00abKafka Streams in azione. Applicazioni e microservizi per il lavoro in tempo reale\u00bb\" src=\"\/wp-content\/uploads\/92ed70f98927d2f778ad14dbc2a5aa26.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nQuesto operatore leftJoin \u00e8 abbastanza semplice. A differenza delle join del capitolo 4, il metodo JoinWindow non viene utilizzato, poich\u00e9 nell'esecuzione della join KStream-KTable per ogni chiave in KTable \u00e8 presente solo una registrazione. Questo tipo di join non \u00e8 limitato nel tempo: la registrazione \u00e8 o presente in KTable o assente. La conclusione principale \u00e8 che gli oggetti KTable possono arricchire KStream con dati di riferimento meno aggiornati.<\/p>\n<p>Ora considereremo un modo pi\u00f9 efficace per arricchire gli eventi da KStream.<\/p>\n<h3>5.3.4. Oggetti GlobalKTable<\/h3>\n<p>\nCome avete capito, c'\u00e8 la necessit\u00e0 di arricchire i flussi di eventi o di aggiungere contesto ad essi. Nel capitolo 4 avete visto connessioni tra due oggetti KStream, e nella sezione precedente - la connessione tra KStream e KTable. In tutti questi casi \u00e8 necessario un nuovo partizionamento del flusso di dati per mappare le chiavi a un nuovo tipo o valore. A volte il partizionamento \u00e8 eseguito esplicitamente, altre volte Kafka Streams lo porta a termine automaticamente. Il partizionamento \u00e8 necessario poich\u00e9 le chiavi sono cambiate e i record devono trovarsi in nuove partizioni; altrimenti, la connessione non sar\u00e0 possibile (discusso nel capitolo 4, nella sezione \u201cPartizionamento dei dati\u201d sotto-sezione 4.2.4).<\/p>\n<h3>Il partizionamento ha il suo costo<\/h3>\n<p>\nLa riconfigurazione richiede costi aggiuntivi \u2014 costi di risorse per la creazione di argomenti intermedi, mantenendo dati duplicati in un altro argomento; implica anche un aumento della latenza a causa della scrittura e lettura da questo argomento. Inoltre, se \u00e8 necessario eseguire il join su pi\u00f9 di un aspetto o dimensione, \u00e8 necessario organizzare i join in catena, visualizzare le registrazioni con nuove chiavi e ripetere il processo di riconfigurazione.<\/p>\n<h3>Join con set di dati di dimensioni inferiori<\/h3>\n<p>\nIn alcuni casi, il volume dei dati di riferimento con cui si prevede di eseguire il join \u00e8 relativamente piccolo, quindi le loro copie complete possono effettivamente essere memorizzate localmente su ciascun nodo. Per tali situazioni, Kafka Streams prevede una classe GlobalKTable.<\/p>\n<p>Le istanze di GlobalKTable sono uniche, poich\u00e9 l'applicazione replica tutti i dati su ciascun nodo. E poich\u00e9 tutti i dati sono presenti su ciascun nodo, non \u00e8 necessario partizionare il flusso di eventi in base alla chiave dei dati di riferimento, rendendolo accessibile a tutte le sezioni. Inoltre, con gli oggetti GlobalKTable, \u00e8 possibile effettuare connessioni senza chiave. Torniamo a uno degli esempi precedenti per dimostrare questa possibilit\u00e0.<\/p>\n<h3>Collegamento di oggetti KStream con oggetti GlobalKTable<\/h3>\n<p>\nNel sottosezione 5.3.2 abbiamo effettuato un'aggregazione a finestra delle transazioni di borsa per i clienti. I risultati di questa aggregazione apparivano circa come segue:<\/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>\nSebbene questi risultati soddisfacessero l'obiettivo, sarebbe stato pi\u00f9 conveniente se venissero visualizzati anche il nome del cliente e la denominazione completa dell'azienda. Per aggiungere il nome del cliente e il nome dell'azienda, \u00e8 possibile effettuare normali collegamenti, ma sar\u00e0 necessario eseguire due mappature delle chiavi e un'ulteriore partizione. Con GlobalKTable, \u00e8 possibile evitare i costi associati a tali operazioni.<\/p>\n<p>Per questo utilizzeremo l'oggetto countStream dell'elenco 5.11 (il codice corrispondente pu\u00f2 essere trovato nel file src\/main\/java\/bbejeck\/chapter_5\/GlobalKTableExample.java), collegandolo a due oggetti GlobalKTable.<\/p>\n<p><img decoding=\"async\" alt=\"Libro \u00abKafka Streams in azione. Applicazioni e microservizi per il lavoro in tempo reale\u00bb\" src=\"\/wp-content\/uploads\/fc4d91bbe062ceb94f5650224840b81e.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nNe abbiamo gi\u00e0 parlato in precedenza, quindi non mi ripeter\u00f2. Ma voglio sottolineare che il codice nella funzione toStream().map \u00e8 astratto in un oggetto funzione per migliorare la leggibilit\u00e0 invece di utilizzare un'espressione lambda inline.<\/p>\n<p>Il passo successivo \u00e8 dichiarare due istanze di GlobalKTable (il codice fornito pu\u00f2 essere trovato nel file src\/main\/java\/bbejeck\/chapter_5\/GlobalKTableExample.java) (elenco 5.12).<\/p>\n<p><img decoding=\"async\" alt=\"Libro \u00abKafka Streams in azione. Applicazioni e microservizi per il lavoro in tempo reale\u00bb\" src=\"\/wp-content\/uploads\/db3918895f174c8cfb5fc927b55f87a1.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p>Si noti che i nomi dei topic sono descritti utilizzando tipi enumerativi.<\/p>\n<p>Ora che abbiamo preparato tutti i componenti, resta solo da scrivere il codice per il join (che pu\u00f2 essere trovato nel file src\/main\/java\/bbejeck\/chapter_5\/GlobalKTableExample.java) (elenco 5.13).<\/p>\n<p><img decoding=\"async\" alt=\"Libro \u00abKafka Streams in azione. Applicazioni e microservizi per il lavoro in tempo reale\u00bb\" src=\"\/wp-content\/uploads\/799360cc99f1920c190a61fd4685d4ff.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nAnche se in questo codice sono presenti due join, questi sono organizzati in una catena, poich\u00e9 nessun risultato singolo viene utilizzato separatamente. I risultati vengono restituiti alla fine dell'intera operazione.<\/p>\n<p>Eseguendo l'operazione di join sopra indicata, otterrete risultati del tipo:<\/p>\n<pre><code class=\"plaintext\">{customer='Barney, Smith' company=\"Exxon\", transactions= 17}<\/code><\/pre>\n<p>\nLa sostanza non \u00e8 cambiata, ma questi risultati sono pi\u00f9 chiari.<\/p>\n<p>Se consideriamo il capitolo 4, hai gi\u00e0 visto diversi tipi di connessioni in azione. Sono elencati nella tabella 5.2. Questa tabella riflette le capacit\u00e0 di connessione valide per la versione 1.0.0 di Kafka Streams; in futuri rilasci potrebbero esserci delle modifiche.<\/p>\n<p><img decoding=\"async\" alt=\"Libro \u00abKafka Streams in azione. Applicazioni e microservizi per il lavoro in tempo reale\u00bb\" src=\"\/wp-content\/uploads\/8e4cf35c64a8431bda43a5e748de275f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nIn conclusione, ricordo l'essenziale: puoi unire flussi di eventi (KStream) e flussi di aggiornamenti (KTable) utilizzando uno stato locale. Inoltre, se la dimensione dei dati di riferimento non \u00e8 troppo grande, puoi utilizzare l'oggetto GlobalKTable. GlobalKTable replica tutte le partizioni su ciascun nodo dell'applicazione Kafka Streams, garantendo cos\u00ec la disponibilit\u00e0 di tutti i dati indipendentemente dalla partizione a cui appartiene la chiave.<\/p>\n<p>In seguito vedremo una funzionalit\u00e0 di Kafka Streams che consente di monitorare le modifiche di stato senza consumare dati dal topic Kafka.<\/p>\n<h3>5.3.5. Stato disponibile per le query<\/h3>\n<p>\nAbbiamo gi\u00e0 eseguito diverse operazioni con lo stato e abbiamo sempre visualizzato i risultati nella console (per scopi di sviluppo) o li abbiamo registrati in un topic (per scopi di produzione). Quando registriamo i risultati in un topic, \u00e8 necessario utilizzare un consumatore Kafka per visualizzarli.<\/p>\n<p>La lettura dei dati da questi topic pu\u00f2 essere considerata una forma di viste materializzate. Per i nostri scopi, possiamo utilizzare la definizione di vista materializzata da \u00abWikipedia\u00bb: \u00ab\u2026un oggetto fisico del database che contiene i risultati dell'esecuzione di una query. Ad esempio, pu\u00f2 essere una copia locale di dati remoti, oppure un sottoinsieme di righe e\/o colonne di una tabella o di risultati di join, o una tabella pivot ottenuta tramite aggregazione\u00bb (https:\/\/en.wikipedia.org\/wiki\/Materialized_view).<\/p>\n<p>Kafka Streams consente anche di eseguire query interattive sui negozi di stato, offrendo la possibilit\u00e0 di leggere direttamente queste rappresentazioni materializzate. \u00c8 importante notare che la query al negozio di stato \u00e8 un'operazione \"solo lettura\". Questo significa che non rischiate di rendere lo stato incoerente durante l'elaborazione dei dati da parte dell'applicazione.<\/p>\n<p>La possibilit\u00e0 di effettuare query dirette sui negozi di stato \u00e8 fondamentale. Significa che \u00e8 possibile creare applicazioni \u2014 dashboard \u2014 senza dover prima recuperare i dati dal consumatore Kafka. Questo aumento di efficienza dell'applicazione \u00e8 possibile poich\u00e9 non \u00e8 necessario riscrivere i dati:<\/p>\n<ul>\n<li>grazie alla localit\u00e0 dei dati, \u00e8 possibile accedervi rapidamente;<\/li>\n<li>si elimina la duplicazione dei dati, poich\u00e9 non vengono registrati in uno storage esterno.<\/li>\n<\/ul>\n<p>\nLa cosa principale che vorrei che tu ricordassi \u00e8: puoi eseguire direttamente query sugli stati dall'applicazione. Non si pu\u00f2 sottovalutare le opportunit\u00e0 che questo ti offre. Invece di consumare dati da Kafka e archiviare registrazioni nel database per l'applicazione, puoi eseguire query sugli archivi di stato con lo stesso risultato. Le richieste dirette agli archivi di stato significano meno codice (assenza di un consumatore) e meno software (non \u00e8 necessario avere una tabella nel database per archiviare i risultati).<\/p>\n<p>Abbiamo coperto una notevole quantit\u00e0 di informazioni in questo capitolo, quindi per il momento interromperemo la nostra discussione sulle query interattive sugli archivi di stato. Ma non preoccuparti: nel capitolo 9 costruiremo una semplice applicazione \u2014 un cruscotto con query interattive. Per dimostrare le query interattive e le possibilit\u00e0 di integrarle nelle applicazioni Kafka Streams, utilizzeremo alcuni degli esempi di questo capitolo e di quelli precedenti.<\/p>\n<h3>Riepilogo<\/h3>\n<p><\/p>\n<ul>\n<li>Gli oggetti KStream rappresentano flussi di eventi, simili a inserimenti in un database. Gli oggetti KTable rappresentano flussi di aggiornamenti, sono pi\u00f9 simili ad aggiornamenti nel database. La dimensione dell'oggetto KTable non aumenta, le vecchie registrazioni vengono sostituite da nuove.<\/li>\n<li>Gli oggetti KTable sono necessari per le operazioni di aggregazione.<\/li>\n<li>Con le operazioni finestra \u00e8 possibile suddividere i dati aggregati in ceste temporali.<\/li>\n<li>Grazie agli oggetti GlobalKTable \u00e8 possibile accedere ai dati di riferimento da qualsiasi punto dell'applicazione, indipendentemente dalla suddivisione in partizioni.<\/li>\n<li>Sono possibili connessioni tra oggetti KStream, KTable e GlobalKTable.<\/li>\n<\/ul>\n<p>\nFino ad ora ci siamo concentrati sulla creazione di applicazioni Kafka Streams utilizzando l'DSL KStream di alto livello. Anche se l'approccio ad alto livello consente di scrivere programmi puliti e concisi, il suo utilizzo comporta un certo compromesso. Lavorare con l'DSL KStream significa aumentare la sinteticit\u00e0 del codice a scapito del controllo. Nel capitolo successivo esploreremo l'API di basso livello dei nodi elaboratori e considereremo altri compromessi. I programmi diventeranno pi\u00f9 lunghi rispetto a prima, ma avremo la possibilit\u00e0 di creare praticamente qualsiasi nodo elaboratore di cui potremmo avere bisogno.<\/p>\n<p>\u2192 Maggiori dettagli sulla disponibilit\u00e0 del libro si possono trovare su <noindex><a rel=\"nofollow\" href=\"https:\/\/www.piter.com\/collection\/best\/product\/kafka-streams-v-deystvii-prilozheniya-i-mikroservisy-dlya-raboty-v-realnom-vremeni\">sito dell'editore<\/a><\/noindex><\/p>\n<p>\u2192 Per gli utenti di Habr, sconto del 25% con il coupon \u2014 <b>Kafka Streams<\/b><\/p>\n<p>\u2192 Dopo il pagamento della versione cartacea del libro, verr\u00e0 inviata una copia elettronica via email.<br \/>\n<br \/>Fonte: <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 4.9.10 - aioseo.com -->\n\t<meta name=\"description\" content=\"\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\" \/>\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\/it\/blog\/administrirovanie\/kniga-kafka-streams-v-dejstvii-prilozheniya-i-mikroservisy-dlya-raboty-v-realnom-vremeni\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 4.9.10\" \/>\n\t\t<meta property=\"og:locale\" content=\"it_IT\" \/>\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:description\" content=\"\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\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/it\/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\udd47Libro \u00abKafka Streams in azione. Applicazioni e microservizi per il lavoro in tempo reale\u00bb | ProHoster","description":"Ciao, membri di Habr! Questo libro \u00e8 adatto a qualsiasi sviluppatore desideroso di comprendere l'elaborazione dei flussi. Comprendere la programmazione distribuita aiuter\u00e0 a esplorare meglio Kafka e Kafka Streams. Conoscere il framework Kafka sarebbe utile, ma non \u00e8 indispensabile: vi spiegher\u00f2 tutto ci\u00f2 che serve. Sia gli sviluppatori esperti di Kafka che i principianti potranno, grazie a questo libro, apprendere come creare applicazioni interessanti.","canonical_url":"https:\/\/prohoster.info\/it\/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":"it_IT","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:description":"\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","og:url":"https:\/\/prohoster.info\/it\/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"},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/35786","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/comments?post=35786"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/35786\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media?parent=35786"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/categories?post=35786"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/tags?post=35786"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}