{"id":38172,"date":"2019-10-31T22:22:05","date_gmt":"2019-10-31T19:22:05","guid":{"rendered":"https:\/\/prohoster.info\/blog\/ponimanie-brokerov-soobshhenij-izuchenie-mehaniki-obmena-soobshheniyami-posredstvom-activemq-i-kafka-glava-3-kafka\/"},"modified":"2019-10-31T22:22:05","modified_gmt":"2019-10-31T19:22:05","slug":"ponimanie-brokerov-soobshhenij-izuchenie-mehaniki-obmena-soobshheniyami-posredstvom-activemq-i-kafka-glava-3-kafka","status":"publish","type":"post","link":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/ponimanie-brokerov-soobshhenij-izuchenie-mehaniki-obmena-soobshheniyami-posredstvom-activemq-i-kafka-glava-3-kafka","title":{"rendered":"Comprendere i broker di messaggi. Studio della meccanica dello scambio di messaggi tramite ActiveMQ e Kafka. Capitolo 3. Kafka","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Proseguimento della traduzione di un piccolo libro:<br \/>\n\u00abUnderstanding Message Brokers\u00bb,<br \/>\nautore: Jakub Korab, editore: O'Reilly Media, Inc., data di pubblicazione: Giugno 2017, ISBN: 9781492049296.<\/p>\n<p>Parte precedente tradotta: <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/466385\/\">Comprensione dei broker di messaggi. Esplorare la meccanica dello scambio di messaggi tramite ActiveMQ e Kafka. Capitolo 1. Introduzione<\/a><\/noindex><br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>CAPITOLO 3<\/h2>\n<p><\/p>\n<h2>Kafka<\/h2>\n<p>\nKafka \u00e8 stato sviluppato in LinkedIn per superare alcune limitazioni dei tradizionali broker di messaggi e per evitare la necessit\u00e0 di configurare pi\u00f9 broker di messaggi per diverse interazioni \u201cpoint-to-point\u201d, come descritto in questo libro nella sezione \u201cScalabilit\u00e0 verticale e orizzontale\u201d a pagina 28. Gli scenari d'uso in LinkedIn si basavano principalmente sull'assorbimento unidirezionale di enormi volumi di dati, come i clic sulle pagine e i log di accesso, consentendo al contempo a questi dati di essere utilizzati da pi\u00f9 sistemi senza influire sulle prestazioni dei produttori o di altri consumatori. In effetti, il motivo per cui Kafka esiste \u00e8 per ottenere un'architettura di scambio di messaggi come quella descritta nel Universal Data Pipeline.<\/p>\n<p>Tenendo presente questo obiettivo finale, sono naturalmente emerse altre esigenze. Kafka deve:<\/p>\n<ul>\n<li>Essere estremamente veloce<\/li>\n<li>Fornire un'ampia larghezza di banda nella gestione dei messaggi<\/li>\n<li>Supportare i modelli \u201cPublisher-Subscriber\u201d e \u201cPoint-to-Point\u201d<\/li>\n<li>Non rallentare con l'aggiunta di consumatori. Ad esempio, le prestazioni sia della queue sia del topic in ActiveMQ peggiorano con l'aumento del numero di consumatori sul destinatario<\/li>\n<li>Essere scalabile orizzontalmente; se un broker che memorizza (persists) i messaggi pu\u00f2 farlo solo alla massima velocit\u00e0 del disco, ha senso superare un singolo esempio di broker per aumentare le prestazioni<\/li>\n<li>Separare l'accesso alla memorizzazione e al recupero dei messaggi<\/li>\n<\/ul>\n<p>\nPer raggiungere tutto ci\u00f2, Kafka ha adottato un'architettura che ha ridefinito i ruoli e le responsabilit\u00e0 dei client e dei broker di messaggistica. Il modello JMS \u00e8 fortemente orientato verso il broker, dove quest'ultimo \u00e8 responsabile della distribuzione dei messaggi, mentre i client devono preoccuparsi solo dell'invio e della ricezione dei messaggi. Kafka, d'altra parte, \u00e8 orientato al client, con quest'ultimo che assume molte funzioni tradizionali del broker, come la distribuzione equa dei messaggi pertinenti tra i consumatori, ricevendo in cambio un broker estremamente veloce e scalabile. Per coloro che hanno lavorato con sistemi di messaggistica tradizionali, lavorare con Kafka richiede cambiamenti fondamentali nella visione.<br \/>\nQuesto approccio ingegneristico ha portato alla creazione di un'infrastruttura di messaggistica capace di aumentare enormemente la capacit\u00e0 rispetto a un broker tradizionale. Come vedremo, questo approccio comporta dei compromessi, che significano che Kafka non \u00e8 adatta per determinati tipi di carichi e software consolidato.<\/p>\n<h3>Modello unificato del destinatario<\/h3>\n<p>\nPer soddisfare i requisiti descritti sopra, Kafka ha unito i messaggi di tipo 'pubblicazione-sottoscrizione' e 'point-to-point' all'interno di un'unica forma di destinatario \u2014 <i>topic<\/i>. Questo pu\u00f2 confondere le persone che hanno lavorato con sistemi di messaggistica, dove la parola 'topic' si riferisce a un meccanismo di broadcasting, dal quale (dal topic) la lettura non \u00e8 affidabile (\u00e8 non durevole). I topic di Kafka devono essere considerati come un tipo ibrido di destinatario, in conformit\u00e0 con la definizione fornita nell'introduzione di questo libro.<\/p>\n<blockquote><p>Nella parte rimanente di questo capitolo, se non indicato esplicitamente altrimenti, il termine 'topic' si riferir\u00e0 ai topic di Kafka.<\/p><\/blockquote>\n<p>\nPer comprendere appieno come si comportano i topic e quali garanzie offrono, dobbiamo prima esaminare come sono implementati in Kafka.<br \/>\n<i>Ogni topic in Kafka ha il proprio registro.<\/i><br \/>\nI produttori che inviano messaggi a Kafka registrano nel registro, mentre i consumatori leggono dal registro utilizzando puntatori che si spostano continuamente in avanti. Periodicamente, Kafka elimina le parti pi\u00f9 vecchie del registro, indipendentemente dal fatto che i messaggi in queste parti siano stati letti o meno. Un elemento centrale del design di Kafka \u00e8 che il broker non si preoccupa se i messaggi siano stati letti o meno: questa \u00e8 la responsabilit\u00e0 del cliente.<\/p>\n<blockquote><p>I termini \"registro\" e \"puntatore\" non si incontrano nella <noindex><a rel=\"nofollow\" href=\"https:\/\/kafka.apache.org\/documentation.html\">documentazione di Kafka<\/a><\/noindex>. Questi termini ben noti sono utilizzati qui per facilitare la comprensione.<\/p><\/blockquote>\n<p>\nQuesto modello \u00e8 completamente diverso da ActiveMQ, dove i messaggi di tutte le code sono memorizzati in un unico registro e il broker contrassegna i messaggi come eliminati dopo che sono stati letti.<br \/>\nOra approfondiamo un po' e consideriamo pi\u00f9 dettagliatamente il registro del topic.<br \/>\nIl registro di Kafka \u00e8 composto da diverse partizioni (<noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/tm\/w2\/yf\/tmw2yf3lanppqtrumxoidotplhi.png\">Figura 3-1<\/a><\/noindex>). Kafka garantisce un rispetto rigoroso dell'ordine in ogni partizione. Ci\u00f2 significa che i messaggi registrati in una partizione in un certo ordine verranno letti nello stesso ordine. Ogni partizione \u00e8 implementata come un file di registro ciclico (rolling) che contiene <i>un sottoinsieme <\/i>(subset) di tutti i messaggi inviati al topic dai suoi produttori. Un topic creato contiene per default una partizione. L'idea delle partizioni \u00e8 il concetto centrale di Kafka per la scalabilit\u00e0 orizzontale.<\/p>\n<p><img decoding=\"async\" alt=\"Comprendere i broker di messaggi. Studio della meccanica dello scambio di messaggi tramite ActiveMQ e Kafka. Capitolo 3. Kafka\" src=\"\/wp-content\/uploads\/2019\/09\/39f41ebcb73ec247656c0dea438158a9.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Figura 3-1. Partizioni di Kafka<\/i><\/p>\n<p>Quando un produttore invia un messaggio a un topic di Kafka, decide in quale partizione inviare il messaggio. Esamineremo questo pi\u00f9 in dettaglio in seguito.<\/p>\n<h2>Lettura dei messaggi<\/h2>\n<p>\nIl cliente che desidera leggere i messaggi gestisce un puntatore denominato <i>gruppo di consumatori (consumer group)<\/i>, che punta a <i>uno spostamento (offset)<\/i> del messaggio nella partizione. Lo spostamento \u00e8 una posizione con un numero in aumento, che inizia da 0 all'inizio della partizione. Questo gruppo di consumatori, a cui si fa riferimento nell'API tramite un identificatore definito dall'utente group_id, corrisponde a <i>un consumatore logico o sistema<\/i>.<\/p>\n<p>La maggior parte dei sistemi che utilizzano il messaging legge i dati dall'indirizzo tramite pi\u00f9 istanze e flussi per l'elaborazione parallela dei messaggi. Pertanto, ci saranno solitamente molte istanze di consumatori che condividono lo stesso gruppo di consumatori.<\/p>\n<p>Il problema della lettura pu\u00f2 essere visto in questo modo:<\/p>\n<ul>\n<li>Il topic ha diverse partizioni<\/li>\n<li>Molteplici gruppi di consumer possono utilizzare il topic contemporaneamente<\/li>\n<li>Un gruppo di consumer pu\u00f2 avere pi\u00f9 esemplari distinti<\/li>\n<\/ul>\n<p>\nQuesto \u00e8 un problema non banale di \u00abmolti a molti\u00bb. Per comprendere come Kafka gestisca le relazioni tra i gruppi di consumer, gli esemplari di consumer e le partizioni, consideriamo una serie di scenari di lettura che diventano progressivamente pi\u00f9 complessi.<\/p>\n<h3>Consumer e gruppi di consumer<\/h3>\n<p>\nPartiamo da un topic con una sola partizione (<noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/6z\/tz\/dh\/6ztzdhqmjweck-z15htxb2xbe28.png\">Figura 3-2<\/a><\/noindex>).<\/p>\n<p><img decoding=\"async\" alt=\"Comprendere i broker di messaggi. Studio della meccanica dello scambio di messaggi tramite ActiveMQ e Kafka. Capitolo 3. Kafka\" src=\"\/wp-content\/uploads\/2019\/09\/46c92e6bd38774dfef3be4bd198bf35d.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Figura 3-2. Il consumer legge dalla partizione<\/i><\/p>\n<p>Quando un esemplare di consumer si connette a questo topic con il proprio group_id, viene assegnata una partizione per la lettura e un offset in quella partizione. La posizione di questo offset \u00e8 configurata nel client, come puntatore alla posizione pi\u00f9 recente (il messaggio pi\u00f9 recente) o alla posizione pi\u00f9 antica (il messaggio pi\u00f9 vecchio). Il consumer richiede (polls) messaggi dal topic, il che porta alla loro lettura sequenziale dal log.<br \/>\nLa posizione dell'offset viene regolarmente committata di nuovo in Kafka e memorizzata, come messaggi nel topic interno <i>_consumer_offsets<\/i>. I messaggi letti non vengono comunque rimossi, a differenza di un broker normale, e il client pu\u00f2 riavvolgere (rewind) l'offset per rielaborare i messaggi gi\u00e0 visualizzati.<\/p>\n<p>Quando si connette un secondo consumer logico, utilizzando un altro group_id, gestisce un secondo puntatore, che \u00e8 indipendente dal primo (<noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/qe\/v1\/yk\/qev1yktga3s-g1gqlynylbe3n9w.png\">Figura 3-3<\/a><\/noindex>). In questo modo, il topic Kafka funziona come una coda, in cui esiste un consumer e, come un comune topic publisher-subscriber (pub-sub), a cui sono iscritti pi\u00f9 consumer, con il vantaggio aggiuntivo che tutti i messaggi vengono conservati e possono essere elaborati pi\u00f9 volte.<\/p>\n<p><img decoding=\"async\" alt=\"Comprendere i broker di messaggi. Studio della meccanica dello scambio di messaggi tramite ActiveMQ e Kafka. Capitolo 3. Kafka\" src=\"\/wp-content\/uploads\/2019\/09\/e9e8b9063ef7367005254d36abb47f4f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Figura 3-3. Due consumer in gruppi di consumer diversi leggono da una partizione<\/i><\/p>\n<h3>Consumer nel gruppo di consumer<\/h3>\n<p>\nQuando un esemplare di consumer legge dati da una partizione, controlla completamente il puntatore e elabora i messaggi, come descritto nel precedente paragrafo.<br \/>\nSe diversi consumer sono connessi con lo stesso group_id a un topic con una sola partizione, l'istanza che si \u00e8 connessa per ultima otterr\u00e0 il controllo del puntatore e da quel momento ricever\u00e0 tutti i messaggi (<noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/0j\/ao\/f2\/0jaof2mdwg3cqvmwemhtxkrltuq.png\">Figura 3-4<\/a><\/noindex>).<\/p>\n<p><img decoding=\"async\" alt=\"Comprendere i broker di messaggi. Studio della meccanica dello scambio di messaggi tramite ActiveMQ e Kafka. Capitolo 3. Kafka\" src=\"\/wp-content\/uploads\/2019\/09\/ec6af819445dad4028f65449a735ae22.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Figura 3-4. Due consumer nella stessa gruppo di consumer leggono da una partizione<\/i><\/p>\n<p>Questa modalit\u00e0 di elaborazione, in cui il numero di istanze di consumer supera il numero di partizioni, pu\u00f2 essere considerata una forma di consumatore monopolistico. Questo pu\u00f2 essere utile se si desidera una clustering \"attivo-passivo\" (o \"caldo-tiepido\") delle vostre istanze di consumer, sebbene l'esecuzione parallela di pi\u00f9 consumer (\"attivo-attivo\" o \"caldo-caldo\") sia molto pi\u00f9 comune rispetto ai consumer in attesa.<\/p>\n<blockquote><p>Questo comportamento di distribuzione dei messaggi, descritto sopra, pu\u00f2 sorprendere rispetto al funzionamento di una normale coda JMS. In questo modello, i messaggi inviati alla coda saranno distribuiti uniformemente tra i due consumer.<\/p><\/blockquote>\n<p>\nPi\u00f9 frequentemente, quando creiamo pi\u00f9 istanze di consumer, lo facciamo per l'elaborazione parallela dei messaggi, per aumentare la velocit\u00e0 di lettura o per migliorare la resilienza del processo di lettura. Poich\u00e9 da una partizione pu\u00f2 leggere un solo consumer alla volta, come viene raggiunto questo in Kafka?<\/p>\n<p>Un modo per farlo \u00e8 utilizzare un'istanza di consumer per leggere tutti i messaggi e passarli a un pool di thread. Sebbene questo approccio aumenti la capacit\u00e0 di elaborazione, aumenta la complessit\u00e0 della logica dei consumer e non migliora la resilienza del sistema di lettura. Se un'istanza di consumer si disconnette a causa di un'interruzione di corrente o di un evento simile, la lettura si interrompe.<\/p>\n<p>Il modo canonico per risolvere questo problema in Kafka \u00e8 utilizzare un<i>O<\/i>numero maggiore di partizioni.<\/p>\n<h3>Partizionamento<\/h3>\n<p>\nLe partizioni sono il meccanismo principale per parallelizzare la lettura e scalare il topic oltre la capacit\u00e0 di un singolo broker. Per comprendere meglio, consideriamo la situazione in cui esiste un topic con due partizioni e a questo topic si iscrive un consumer (<noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/en\/9g\/ct\/en9gct0o017cqp8buawguwlscty.png\">Figura 3-5<\/a><\/noindex>).<\/p>\n<p><img decoding=\"async\" alt=\"Comprendere i broker di messaggi. Studio della meccanica dello scambio di messaggi tramite ActiveMQ e Kafka. Capitolo 3. Kafka\" src=\"\/wp-content\/uploads\/2019\/09\/cc766bf69af22698aacc3f1ac70b067f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Figura 3-5. Un consumatore legge da pi\u00f9 partizioni<\/i><\/p>\n<p>In questo scenario, al consumatore viene dato il controllo sui puntatori corrispondenti al suo group_id in entrambe le partizioni e inizia a leggere i messaggi da entrambe le partizioni.<br \/>\nQuando viene aggiunto un ulteriore consumatore a questo argomento per lo stesso group_id, Kafka ri-assegna (reallocate) una delle partizioni dal primo al secondo consumatore. Dopo di che, ogni istanza del consumatore legger\u00e0 da una partizione dell'argomento (<noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/8b\/a0\/um\/8ba0umn2yzr9yy3vztonhdfiub0.png\">Figura 3-6<\/a><\/noindex>).<\/p>\n<p>Per garantire l'elaborazione dei messaggi in parallelo su 20 thread, saranno necessarie almeno 20 partizioni. Se ci sono meno partizioni, ci saranno consumatori che non hanno nulla di cui occuparsi, come descritto in precedenza nella discussione sui consumatori monopolisti.<\/p>\n<p><img decoding=\"async\" alt=\"Comprendere i broker di messaggi. Studio della meccanica dello scambio di messaggi tramite ActiveMQ e Kafka. Capitolo 3. Kafka\" src=\"\/wp-content\/uploads\/2019\/09\/a3c4001e4a5b92d53b6f529b2633254a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Figura 3-6. Due consumatori nella stessa gruppo di consumatori leggono da partizioni diverse<\/i><\/p>\n<p>Questo schema riduce significativamente la complessit\u00e0 del lavoro del broker Kafka rispetto alla distribuzione dei messaggi necessaria per supportare la coda JMS. Qui non \u00e8 necessario preoccuparsi dei seguenti aspetti:<\/p>\n<ul>\n<li>Quale consumatore dovrebbe ricevere il prossimo messaggio, basato sulla distribuzione a turno (round-robin), la capacit\u00e0 corrente dei buffer di pre-lettura o i messaggi precedenti (come per i gruppi di messaggi JMS).<\/li>\n<li>Quali messaggi sono stati inviati a quali consumatori e se devono essere consegnati di nuovo in caso di errore.<\/li>\n<\/ul>\n<p>\nTutto ci\u00f2 che deve fare il broker Kafka \u00e8 trasmettere i messaggi al consumatore in modo sequenziale, quando quest'ultimo li richiede.<\/p>\n<p>Tuttavia, le esigenze di parallelizzazione della lettura e di reinvio dei messaggi falliti non scompaiono, ma la responsabilit\u00e0 per esse passa semplicemente dal broker al client. Questo significa che devono essere considerate nel vostro codice.<\/p>\n<h2>Invio dei messaggi<\/h2>\n<p>\nLa responsabilit\u00e0 di decidere a quale partizione inviare un messaggio ricade sul produttore di quel messaggio. Per comprendere il meccanismo con cui questo avviene, \u00e8 necessario prima esaminare cosa stiamo effettivamente inviando.<\/p>\n<p>Mentre in JMS utilizziamo una struttura di messaggio con metadati (intestazioni e propriet\u00e0) e un corpo contenente il payload, in Kafka il messaggio \u00e8 <i>una coppia \"chiave-valore\"<\/i>. Il payload del messaggio viene inviato come valore (value). La chiave, d'altra parte, viene utilizzata principalmente per il partizionamento e deve contenere <i>una chiave specifica per la logica aziendale<\/i>, per collocare i messaggi correlati nella stessa partizione.<\/p>\n<p>Nella Capitolo 2 abbiamo discusso di uno scenario di scommesse online, quando eventi correlati devono essere elaborati in ordine da un unico consumatore:<\/p>\n<ol>\n<li>L'account utente \u00e8 stato configurato.<\/li>\n<li>I soldi vengono accreditati sul conto.<\/li>\n<li>Viene effettuata una scommessa che preleva soldi dal conto.<\/li>\n<\/ol>\n<p>\nSe ogni evento rappresenta un messaggio inviato a un topic, in questo caso la chiave naturale sar\u00e0 l'ID dell'account.<br \/>\nQuando un messaggio viene inviato utilizzando l'API Kafka Producer, viene passato alla funzione di partizionamento, che, considerato il messaggio e lo stato attuale del cluster Kafka, restituisce l'ID della partizione in cui il messaggio deve essere inviato. Questa funzione \u00e8 implementata in Java tramite l'interfaccia Partitioner.<\/p>\n<p>Questa interfaccia \u00e8 la seguente:<\/p>\n<pre><code class=\"java\">interface Partitioner {\n    int partition(String topic,\n        Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster);\n}<\/code><\/pre>\n<p>\nL'implementazione del Partitioner per la determinazione della partizione utilizza per impostazione predefinita un algoritmo di hash del chiave (general-purpose hashing algorithm over the key) o round-robin, se la chiave non \u00e8 specificata. Questo valore predefinito funziona bene nella maggior parte dei casi. Tuttavia, in futuro, potresti voler scrivere la tua.<\/p>\n<h3>Scrittura della propria strategia di partizionamento<\/h3>\n<p>\nConsideriamo un esempio in cui desideri inviare metadati insieme al payload del messaggio. Il payload nel nostro esempio \u00e8 un'istruzione per effettuare un deposito su un conto di gioco. L'istruzione \u00e8 ci\u00f2 che vorremmo garantire di non modificare durante la trasmissione e vogliamo assicurarci che solo un sistema di fiducia superiore possa avviare questa istruzione. In questo caso, i sistemi mittente e destinatario concordano sull'uso della firma per verificare l'autenticit\u00e0 del messaggio.<br \/>\nNell'ordinario JMS definiamo semplicemente la propriet\u00e0 \"firma del messaggio\" e la aggiungiamo al messaggio. Tuttavia, Kafka non ci offre un meccanismo per trasmettere metadati \u2014 solo chiave e valore.<\/p>\n<p>Poich\u00e9 il valore \u00e8 il payload del bonifico bancario, la cui integrit\u00e0 vogliamo mantenere, non ci resta altro che definire la struttura dei dati da utilizzare nella chiave. Supponendo di aver bisogno di un identificatore dell'account per il partizionamento, dato che tutti i messaggi relativi all'account devono essere elaborati in sequenza, ipotizzeremo la seguente struttura JSON:<\/p>\n<pre><code class=\"json\">{\n  \"signature\": \"541661622185851c248b41bf0cea7ad0\",\n  \"accountId\": \"10007865234\"\n}<\/code><\/pre>\n<p>\nPoich\u00e9 il valore della firma varier\u00e0 a seconda del payload, la strategia di hashing predefinita dell'interfaccia Partitioner non raggrupper\u00e0 in modo affidabile i messaggi correlati. Pertanto, dovremo scrivere la nostra strategia, che analizzer\u00e0 questa chiave e divider\u00e0 (partition) il valore accountId.<\/p>\n<blockquote><p>Kafka include checksum per rilevare la corruzione dei messaggi nello storage e ha un completo insieme di funzionalit\u00e0 di sicurezza. Anche in questo caso, a volte emergono requisiti specifici del settore, come quello di cui sopra.<\/p><\/blockquote>\n<p>\nLa strategia di partizionamento personalizzata deve garantire che tutti i messaggi correlati finiscano in una sola partizione. Anche se questo sembra semplice, il requisito pu\u00f2 complicarsi a causa dell'importanza di mantenere l'ordine dei messaggi correlati e del numero fisso di partizioni nel topic.<\/p>\n<p>Il numero di partizioni nel topic pu\u00f2 cambiare nel tempo, poich\u00e9 possono essere aggiunte se il traffico supera le aspettative iniziali. Pertanto, le chiavi dei messaggi possono essere associate alla partizione in cui sono state inizialmente inviate, implicando parte dello stato che deve essere distribuito tra le istanze del produttore.<\/p>\n<p>Un altro fattore da considerare \u00e8 l'uniformit\u00e0 della distribuzione dei messaggi tra le partizioni. Di norma, le chiavi non sono distribuite uniformemente tra i messaggi, e le funzioni hash non garantiscono una distribuzione equa dei messaggi per un piccolo insieme di chiavi.<br \/>\n\u00c8 importante notare che, qualunque sia la decisione su come dividere i messaggi, il delimitatore stesso potrebbe dover essere riutilizzato.<\/p>\n<p>Esaminiamo il requisito della replica dei dati tra cluster Kafka in diverse localit\u00e0 geografiche. A questo scopo, Kafka viene fornito con uno strumento da riga di comando chiamato MirrorMaker, utilizzato per leggere i messaggi da un cluster e trasferirli in un altro.<\/p>\n<p>MirrorMaker deve comprendere le chiavi del topic replicato per mantenere l'ordine relativo tra i messaggi durante la replica tra i cluster, poich\u00e9 il numero di partizioni per quel topic potrebbe non corrispondere nei due cluster.<\/p>\n<p>Le strategie di partizionamento personalizzate si incontrano relativamente raramente, poich\u00e9 il default hashing o il round-robin funzionano con successo nella maggior parte degli scenari. Tuttavia, se hai bisogno di garanzie rigorose di ordinamento o se \u00e8 necessario estrarre metadati dai payload, il partizionamento \u00e8 ci\u00f2 su cui dovresti soffermarti con maggiore attenzione.<\/p>\n<p>I vantaggi di scalabilit\u00e0 e prestazioni di Kafka derivano dal trasferimento di alcune responsabilit\u00e0 di un tradizionale broker al client. In questo caso, si decide di distribuire messaggi potenzialmente correlati su pi\u00f9 consumatori che funzionano in parallelo.<\/p>\n<blockquote><p>Anche i broker JMS devono affrontare tali requisiti. \u00c8 interessante notare che il meccanismo di invio di messaggi correlati allo stesso consumatore, implementato attraverso i JMS Message Groups (una variante della strategia di bilanciamento del carico sticky load balancing (SLB)), richiede anche che l'invio contrassegni i messaggi come correlati. Nel caso di JMS, il broker \u00e8 responsabile dell'invio di questo gruppo di messaggi correlati a un consumatore tra molti e del trasferimento della propriet\u00e0 del gruppo se il consumatore si disconnette.<\/p><\/blockquote>\n<p><\/p>\n<h2>Accordi per il produttore<\/h2>\n<p>\nIl partizionamento non \u00e8 l'unico aspetto da considerare quando si inviano messaggi. Esaminiamo i metodi send () della classe Producer nell'API Java:<\/p>\n<pre><code class=\"java\">Future  send(ProducerRecord  record);\nFuture  send(ProducerRecord  record, Callback callback);<\/code><\/pre>\n<p>\n\u00c8 importante notare che entrambi i metodi restituiscono un Future, il che indica che l'operazione di invio non viene eseguita immediatamente. Di conseguenza, il messaggio (ProducerRecord) viene scritto nel buffer di invio per ogni partizione attiva e viene inviato al broker tramite un thread in background nella libreria cliente Kafka. Sebbene questo renda il lavoro incredibilmente veloce, significa che un'applicazione scritta in modo inadeguato potrebbe perdere messaggi se il suo processo viene interrotto.<\/p>\n<p>Come sempre, c'\u00e8 un modo per rendere l'operazione di invio pi\u00f9 affidabile a scapito delle prestazioni. Le dimensioni di questo buffer possono essere impostate a 0, e il thread dell'applicazione di invio sar\u00e0 costretto ad attendere fino al completamento della trasmissione del messaggio al broker, nel modo seguente:<\/p>\n<pre><code class=\"java\">RecordMetadata metadata = producer.send(record).get();<\/code><\/pre>\n<p><\/p>\n<h2>Ancora una volta sulla lettura dei messaggi<\/h2>\n<p>\nLa lettura dei messaggi presenta ulteriori complessit\u00e0 di cui \u00e8 necessario discutere. A differenza dell'API JMS, che pu\u00f2 avviare un ascoltatore di messaggi in risposta all'arrivo di un messaggio, l'interfaccia <i>Consumer <\/i>Kafka esegue solo polling. Esaminiamo pi\u00f9 da vicino il metodo <i>poll ()<\/i>, utilizzato per questo scopo:<\/p>\n<pre><code class=\"java\">ConsumerRecords  poll(long timeout);<\/code><\/pre>\n<p>\nIl valore restituito dal metodo \u00e8 una struttura contenitore che contiene pi\u00f9 oggetti <i>ConsumerRecord <\/i>da potenziali pi\u00f9 partizioni. <i>ConsumerRecord <\/i>\u00e8, di per s\u00e9, un oggetto contenitore per la coppia chiave-valore con metadati pertinenti, come la partizione da cui \u00e8 stato ricevuto.<\/p>\n<p>Come discusso nel Capitolo 2, dobbiamo ricordare costantemente cosa succede ai messaggi dopo il loro trattamento, sia che sia andato a buon fine che non, ad esempio nel caso in cui il cliente non riesca a elaborare un messaggio o si interrompa. In JMS questo veniva gestito attraverso la modalit\u00e0 di conferma (acknowledgement mode). Il broker eliminer\u00e0 il messaggio elaborato con successo oppure riporter\u00e0 il messaggio non elaborato o fallito (a condizione che siano state utilizzate transazioni). <br \/>\nKafka funziona in modo completamente diverso. I messaggi non vengono eliminati dal broker dopo la lettura e la responsabilit\u00e0 di ci\u00f2 che accade in caso di errore \u00e8 nel codice di lettura stesso.<\/p>\n<p>Come abbiamo gi\u00e0 detto, un gruppo di consumatori \u00e8 legato allo spostamento nel log. La posizione nel log associata a questo spostamento corrisponde al successivo messaggio che sar\u00e0 emesso in risposta a <i>poll ()<\/i>Il momento in cui questo offset aumenta \u00e8 fondamentale nella lettura.<\/p>\n<p>Tornando al modello di lettura discusso in precedenza, l'elaborazione del messaggio avviene in tre fasi:<\/p>\n<ol>\n<li>Estrarre il messaggio da leggere.<\/li>\n<li>Elaborare il messaggio.<\/li>\n<li>Confermare il messaggio.<\/li>\n<\/ol>\n<p>\nIl consumatore Kafka viene fornito con un'opzione di configurazione <i>enable.auto.commit<\/i>. Questa \u00e8 un'impostazione frequentemente utilizzata di default, come di solito accade con le impostazioni che contengono la parola \"auto\".<\/p>\n<p>Fino a Kafka 0.10, il client che utilizzava questo parametro inviava l'offset dell'ultimo messaggio letto al successivo richiamo <i>poll ()<\/i> dopo l'elaborazione. Questo significava che eventuali messaggi gi\u00e0 estratti (fetched) avrebbero potuto essere elaborati nuovamente, se il client li avesse gi\u00e0 elaborati, ma fosse stato improvvisamente interrotto prima del richiamo <i>poll ()<\/i>. Poich\u00e9 il broker non conserva alcuno stato riguardo a quante volte un messaggio \u00e8 stato letto, il successivo consumatore che estrae questo messaggio non sapr\u00e0 che \u00e8 successo qualcosa di negativo. Questo comportamento era pseudo-transazionale. Lo spostamento veniva registrato solo in caso di elaborazione riuscita del messaggio, ma se il cliente interrompeva il suo lavoro, il broker inviava nuovamente lo stesso messaggio a un altro cliente. Questo comportamento corrispondeva alla garanzia di consegna dei messaggi \u00ab<i>almeno una volta<\/i>&#171;.<\/p>\n<p>In Kafka 0.10, il codice del client \u00e8 stato modificato in modo tale che il commit iniziava a essere eseguito periodicamente dalla libreria cliente, in conformit\u00e0 con l'impostazione <i>auto.commit.interval.ms<\/i>. Questo comportamento si colloca a met\u00e0 strada tra le modalit\u00e0 JMS AUTO_ACKNOWLEDGE e DUPS_OK_ACKNOWLEDGE. Quando si utilizza l'auto-commit, i messaggi potrebbero essere confermati indipendentemente dal fatto che fossero stati effettivamente elaborati - questo potrebbe verificarsi nel caso di un consumatore lento. Se il consumatore andava in errore, i messaggi venivano estratti dal successivo consumatore a partire dalla posizione confermata, il che poteva portare a saltare un messaggio. In tal caso, Kafka non perdeva messaggi; il codice di lettura semplicemente non li elaborava.<\/p>\n<p>Questa modalit\u00e0 ha le stesse prospettive di quella nella versione 0.9: i messaggi possono essere elaborati, ma in caso di errore, l'offset potrebbe non essere stato confermato, il che potrebbe potenzialmente portare a una duplicazione della consegna. Pi\u00f9 messaggi estrai durante l'esecuzione <i>poll ()<\/i>, maggiore \u00e8 questo problema.<\/p>\n<p>Come discusso nella sezione \u00abLettura dei messaggi dalla coda\u00bb a pagina 21, nel sistema di messaging non esiste il concetto di consegna unica del messaggio, se si considerano le modalit\u00e0 di errore.<\/p>\n<p>In Kafka ci sono due modi per registrare (commit) l'offset: automaticamente e manualmente. In entrambi i casi, i messaggi possono essere elaborati pi\u00f9 volte, nel caso in cui un messaggio sia stato elaborato, ma si sia verificato un errore prima del commit. Puoi anche non elaborare affatto un messaggio se il commit \u00e8 avvenuto in background e il tuo codice \u00e8 stato completato prima di iniziare l'elaborazione (probabilmente in Kafka 0.9 e versioni precedenti).<\/p>\n<p>Per gestire manualmente il processo di commit dell'offset, puoi utilizzare l'API del consumer di Kafka, impostando il parametro <i>enable.auto.commit<\/i> su false e chiamando esplicitamente uno dei seguenti metodi:<\/p>\n<pre><code class=\"java\">void commitSync();\nvoid commitAsync();<\/code><\/pre>\n<p>\nSe desideri elaborare un messaggio \u00abalmeno una volta\u00bb, devi committare l'offset manualmente con <i>commitSync ()<\/i>, eseguendo questo comando immediatamente dopo l'elaborazione dei messaggi.<\/p>\n<p>Questi metodi non consentono di confermare i messaggi fino a quando non vengono elaborati, ma non fanno nulla per prevenire la potenziale duplicazione dell'elaborazione, creando nel contempo l'illusione di transazionalit\u00e0. In Kafka non ci sono transazioni. Il client non ha la possibilit\u00e0 di fare quanto segue:<\/p>\n<ul>\n<li>Annullare automaticamente (rollback) un messaggio non riuscito. I consumer devono gestire le eccezioni che si verificano a causa di payload problematici e disconnessioni del backend, poich\u00e9 non possono contare sulla riconsegna dei messaggi da parte del broker.<\/li>\n<li>Inviare messaggi a pi\u00f9 topic all'interno di un'unica operazione atomica. Come vedremo presto, il controllo su diversi topic e partizioni pu\u00f2 trovarsi su diverse macchine nel cluster Kafka, che non coordinano le transazioni durante l'invio. Al momento della scrittura di questo articolo, \u00e8 stato fatto un certo lavoro per rendere questo possibile tramite KIP-98.<\/li>\n<li>Collegare la lettura di un messaggio da un topic all'invio di un altro messaggio a un altro topic. Ancora una volta, l'architettura di Kafka dipende da molte macchine indipendenti che funzionano come un'unica rete e non vengono fatti tentativi per nascondere questo. Ad esempio, non esistono componenti API che permettano di collegare <i>Consumer <\/i>e <i>Producer <\/i>nella transazione. In JMS questo \u00e8 garantito dall'oggetto <i>Session<\/i>, da cui vengono creati <i>MessageProducers <\/i>e <i>MessageConsumers<\/i>.<\/li>\n<\/ul>\n<p>\nSe non possiamo fare affidamento sulle transazioni, come possiamo garantire una semantica pi\u00f9 vicina a quella fornita dai tradizionali sistemi di messaggistica?<\/p>\n<p>Se c'\u00e8 la possibilit\u00e0 che l'offset del consumer possa aumentare prima che il messaggio venga elaborato, ad esempio durante un guasto del consumer, allora il consumer non ha alcun modo di sapere se il suo gruppo di consumer ha saltato messaggi quando gli viene assegnata una partizione. Pertanto, una delle strategie \u00e8 quella di riavvolgere l'offset sulla posizione precedente. L'API del consumer di Kafka fornisce i seguenti metodi per questo:<\/p>\n<pre><code class=\"java\">void seek(TopicPartition partition, long offset);\nvoid seekToBeginning(Collection  partitions);<\/code><\/pre>\n<p>\nSanitizer.replaceElementWithChildren() <i>seek ()<\/i> pu\u00f2 essere utilizzato con il metodo <br \/>\n<i>offsetsForTimes (Map timestampsToSearch)<\/i> per riavvolgere a uno stato in un particolare momento nel passato.<\/p>\n<p>Implicitamente, l'uso di questo approccio significa che \u00e8 molto probabile che alcuni messaggi precedentemente elaborati vengano letti ed elaborati di nuovo. Per evitare ci\u00f2, possiamo utilizzare la lettura idempotente, come descritto nel Capitolo 4, per tracciare i messaggi gi\u00e0 visualizzati ed escludere i duplicati.<\/p>\n<p>In alternativa, il codice del tuo consumer potrebbe essere semplice, se \u00e8 accettabile la perdita o la duplicazione dei messaggi. Quando consideriamo scenari d'uso per i quali Kafka \u00e8 tipicamente utilizzato, come l'elaborazione di eventi di log, metriche, tracciamento dei clic, ecc., ci rendiamo conto che la perdita di messaggi singoli avr\u00e0 probabilmente un impatto trascurabile sulle applicazioni circostanti. In tali casi, i valori predefiniti sono assolutamente accettabili. D'altra parte, se la tua applicazione deve trasmettere pagamenti, devi prestare particolare attenzione a ciascun singolo messaggio. Tutto si riduce al contesto.<\/p>\n<p>Osservazioni personali mostrano che, con l'aumentare dell'intensit\u00e0 dei messaggi, il valore di ciascun singolo messaggio diminuisce. Messaggi di grande volume diventano generalmente preziosi se considerati in forma aggregata.<\/p>\n<h2>Alta disponibilit\u00e0 (High Availability)<\/h2>\n<p>\nL'approccio di Kafka alla disponibilit\u00e0 elevata \u00e8 sostanzialmente diverso rispetto a quello di ActiveMQ. Kafka \u00e8 progettata su cluster scalabili orizzontalmente, in cui tutte le istanze del broker ricevono e inviano messaggi contemporaneamente.<\/p>\n<p>Un cluster Kafka \u00e8 composto da pi\u00f9 istanze di broker che operano su server diversi. Kafka \u00e8 stata progettata per funzionare su hardware autonomo comune, dove ogni nodo ha il proprio storage dedicato. L'uso di storage di rete (SAN) non \u00e8 raccomandato, poich\u00e9 pi\u00f9 nodi computazionali possono competere per gli intervalli di tempo dello storage e creare conflitti.<i>La<\/i>intervalli di archiviazione e creare conflitti.<\/p>\n<p>Kafka \u00e8 <i>un sistema sempre acceso.<\/i> Molti grandi utilizzatori di Kafka non spengono mai i loro cluster e il software assicura sempre l'aggiornamento tramite un riavvio sequenziale. Ci\u00f2 \u00e8 raggiunto garantendo la compatibilit\u00e0 con le versioni precedenti per i messaggi e le interazioni tra broker.<\/p>\n<p>I broker sono collegati al cluster di server <noindex><a rel=\"nofollow\" href=\"http:\/\/zookeeper.apache.org\">ZooKeeper<\/a><\/noindex>, che funge da registro delle configurazioni e viene utilizzato per coordinare i ruoli di ciascun broker. ZooKeeper \u00e8 a sua volta un sistema distribuito che garantisce alta disponibilit\u00e0 tramite la replicazione delle informazioni stabilendo <i>un quorum.<\/i>.<\/p>\n<p>Nel caso base, un topic viene creato nel cluster Kafka con le seguenti propriet\u00e0:<\/p>\n<ul>\n<li>Numero di partizioni. Come discusso in precedenza, il valore preciso utilizzato qui dipende dal livello desiderato di lettura parallela.<\/li>\n<li>Il fattore di replica determina quanti istanze del broker nel cluster devono contenere i log per questa partizione.<\/li>\n<\/ul>\n<p>\nUtilizzando ZooKeepers per la coordinazione, Kafka cerca di distribuire in modo equo le nuove partizioni tra i broker nel cluster. Questo viene fatto da un'istanza che svolge il ruolo di Controller.<\/p>\n<p>Durante il runtime <i>per ciascuna partizione del topic<\/i> <i>Controller <\/i>assegna ai broker i ruoli di <i>leader <\/i>(leader, master, capo) <i>seguaci <\/i>(follower, schiavi, subordinati). Il broker che funge da leader per questa partizione \u00e8 responsabile della ricezione di tutti i messaggi inviati dai produttori e della distribuzione dei messaggi ai consumatori. Quando vengono inviati messaggi a una partizione del topic, vengono replicati su tutti i nodi broker che fungono da follower per questa partizione. Ogni nodo che contiene i log per la partizione \u00e8 chiamato <i>replica<\/i>. Il broker pu\u00f2 fungere da leader per alcune partizioni e da follower per altre.<\/p>\n<p>Il follower che contiene tutti i messaggi memorizzati dal leader \u00e8 chiamato <i>replica sincronizzata<\/i> (replica che \u00e8 in stato sincronizzato, in-sync replica). Se il broker che funge da leader per la partizione si disconnette, qualsiasi broker che \u00e8 in uno stato aggiornato o sincronizzato per questa partizione pu\u00f2 assumere il ruolo di leader. Questo \u00e8 un design incredibilmente resiliente.<\/p>\n<p>Una parte della configurazione del produttore \u00e8 il parametro <i>acks<\/i>, che definisce quante repliche devono riconoscere (acknowledge) la ricezione di un messaggio prima che il flusso dell'applicazione continui a inviare: 0, 1 o tutte. Se \u00e8 impostato un valore <i>all<\/i>, allora al ricevimento del messaggio il leader invier\u00e0 una conferma (confirmation) al produttore non appena riceve conferme (acknowledgements) da pi\u00f9 repliche (compresa se stessa), come definito nella configurazione del topic <i>min.insync.replicas<\/i> (di default 1). Se il messaggio non pu\u00f2 essere replicato con successo, il produttore generer\u00e0 un'eccezione per l'applicazione (<i>NotEnoughReplicas<\/i> o <i>NotEnoughReplicasAfterAppend<\/i>).<\/p>\n<p>In una configurazione tipica, viene creato un topic con un fattore di replica di 3 (1 leader, 2 follower per ogni partizione) e il parametro <i>min.insync.replicas<\/i> \u00e8 impostato a 2. In questo caso, il cluster permetter\u00e0 a uno dei broker che gestiscono la partizione del topic di disconnettersi senza influenzare le applicazioni client.<\/p>\n<p>Questo ci riporta al compromesso gi\u00e0 noto tra prestazioni e affidabilit\u00e0. La replicazione avviene a causa del tempo aggiuntivo necessario per l'attesa delle conferme (acknowledgments) dai follower. Anche se, poich\u00e9 avviene in parallelo, la replicazione, su almeno tre nodi, ha le stesse prestazioni che su due (ignorando l'aumento dell'uso della larghezza di banda della rete).<\/p>\n<p>Utilizzando questo schema di replica, Kafka evita abilmente la necessit\u00e0 di garantire la registrazione fisica di ogni messaggio su disco con l'operazione <i>sync ()<\/i>. Ogni messaggio inviato dal produttore verr\u00e0 registrato nel log della partizione, ma, come discusso nel Capitolo 2, la registrazione nel file viene inizialmente eseguita nel buffer del sistema operativo. Se questo messaggio viene replicato su un'altra istanza di Kafka e si trova nella sua memoria, la perdita del leader non significa che il messaggio sia stato perso: pu\u00f2 essere gestito da una replica sincronizzata.<br \/>\nEvitare la necessit\u00e0 di eseguire l'operazione <i>sync ()<\/i> significa che Kafka pu\u00f2 ricevere messaggi alla velocit\u00e0 con cui pu\u00f2 registrarli in memoria. E viceversa, pi\u00f9 a lungo si pu\u00f2 evitare il flush della memoria su disco, meglio \u00e8. Per questo motivo, non \u00e8 raro che ai broker Kafka venga assegnata una memoria di 64 GB o pi\u00f9. Questo utilizzo della memoria significa che un'istanza di Kafka pu\u00f2 facilmente operare a velocit\u00e0 migliaia di volte superiori rispetto a un tradizionale broker di messaggi.<\/p>\n<p>Kafka pu\u00f2 anche essere configurato per applicare l'operazione <i>sync ()<\/i> a pacchetti di messaggi. Poich\u00e9 tutto in Kafka \u00e8 orientato al lavoro con pacchetti, questo funziona davvero bene per molti scenari di utilizzo ed \u00e8 uno strumento utile per gli utenti che richiedono garanzie molto forti. Gran parte della pura performance di Kafka \u00e8 legata ai messaggi inviati al broker in forma di pacchetti, e al fatto che questi messaggi vengono letti dal broker in blocchi sequenziali tramite <noindex><a rel=\"nofollow\" href=\"http:\/\/www.linuxjournal.com\/article\/6345\">zero-copy<\/a><\/noindex> operazioni (operazioni in cui non viene eseguito il compito di copiare i dati da un'area di memoria a un'altra). Quest'ultima rappresenta un grande vantaggio in termini di performance e risorse ed \u00e8 possibile solo grazie all'utilizzo della struttura dati sottostante del log che definisce lo schema della partizione.<\/p>\n<p>In un cluster Kafka \u00e8 possibile ottenere prestazioni molto pi\u00f9 elevate rispetto a un singolo broker Kafka, poich\u00e9 le partizioni del topic possono scalare orizzontalmente su molte macchine separate.<\/p>\n<h2>Conclusioni<\/h2>\n<p>\nIn questo capitolo abbiamo esaminato come l'architettura di Kafka ridefinisca i rapporti tra clienti e broker, per fornire un incredibile flusso di messaggi con una capacit\u00e0 di gran lunga superiore rispetto a un normale broker di messaggi. Abbiamo discusso le funzionalit\u00e0 che sfrutta per raggiungere questo obiettivo e fornito una breve panoramica dell'architettura delle applicazioni che supportano tale funzionalit\u00e0. Nel prossimo capitolo esamineremo le problematiche comuni che le applicazioni basate sullo scambio di messaggi devono affrontare e discuteremo le strategie per affrontarle. Concluderemo il capitolo delineando come riflettere sulle tecnologie di messaggistica in generale, in modo da poter valutarne l'idoneit\u00e0 per i tuoi scenari d'uso.<\/p>\n<p>Parte precedente tradotta: <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/466385\/\">Comprensione dei broker di messaggi. Studio della meccanica dello scambio di messaggi tramite ActiveMQ e Kafka. Capitolo 1<\/a><\/noindex><\/p>\n<p><b> Traduzione eseguita: <noindex><a rel=\"nofollow\" href=\"http:\/\/tele.gg\/middle_java\">tele.gg\/middle_java<\/a><\/noindex><\/b><\/p>\n<p><i>Continua&#8230;<\/i><\/p>\n<p class=\"for_users_only_msg\">Solo gli utenti registrati possono partecipare al sondaggio. <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/auth\/login\/\">Accedi<\/a><\/noindex>, per favore.<\/p>\n<h2 class=\"default-block__polling-title\">Kafka \u00e8 utilizzato nella tua organizzazione?<\/h2>\n<ul class=\"content-list content-list_polling\">\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    S\u00ec<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    No<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    In passato era utilizzato, ora no<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Prevediamo di utilizzarlo<\/p>\n<\/li>\n<\/ul>\n<p>    Hanno votato 38 utenti. 8 utenti si sono astenuti.<br \/>\n<br \/>Fonte: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/466585\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043a\u043d\u0438\u0433\u0438: \u00abUnderstanding Message Brokers\u00bb, \u0430\u0432\u0442\u043e\u0440: Jakub Korab, \u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u043e: O&#8217;Reilly Media, Inc., \u0434\u0430\u0442\u0430 \u0438\u0437\u0434\u0430\u043d\u0438\u044f: June 2017, ISBN: 9781492049296. \u041f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0430\u044f \u043f\u0435\u0440\u0435\u0432\u0435\u0434\u0435\u043d\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c: \u041f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u0431\u0440\u043e\u043a\u0435\u0440\u043e\u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. \u0418\u0437\u0443\u0447\u0435\u043d\u0438\u0435 \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0438 \u043e\u0431\u043c\u0435\u043d\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438 \u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e\u043c ActiveMQ \u0438 Kafka. \u0413\u043b\u0430\u0432\u0430 1. \u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0413\u041b\u0410\u0412\u0410 3 Kafka Kafka \u0431\u044b\u043b\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u0430 \u0432 LinkedIn \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043e\u0431\u043e\u0439\u0442\u0438 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f \u0442\u0440\u0430\u0434\u0438\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u0431\u0440\u043e\u043a\u0435\u0440\u043e\u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0438 [&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-38172","post","type-post","status-publish","format-standard","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.2 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043a\u043d\u0438\u0433\u0438: \u00abUnderstanding Message Brokers\u00bb, \u0430\u0432\u0442\u043e\u0440: Jakub Korab, \u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u043e: O&#039;Reilly Media, Inc., \u0434\u0430\u0442\u0430 \u0438\u0437\u0434\u0430\u043d\u0438\u044f: June 2017, ISBN: 9781492049296. \u041f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0430\u044f \u043f\u0435\u0440\u0435\u0432\u0435\u0434\u0435\u043d\u043d\u0430\u044f.\" \/>\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\/ponimanie-brokerov-soobshhenij-izuchenie-mehaniki-obmena-soobshheniyami-posredstvom-activemq-i-kafka-glava-3-kafka\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2\" \/>\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\u041f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u0431\u0440\u043e\u043a\u0435\u0440\u043e\u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. \u0418\u0437\u0443\u0447\u0435\u043d\u0438\u0435 \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0438 \u043e\u0431\u043c\u0435\u043d\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438 \u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e\u043c ActiveMQ \u0438 Kafka. \u0413\u043b\u0430\u0432\u0430 3. Kafka | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043a\u043d\u0438\u0433\u0438: \u00abUnderstanding Message Brokers\u00bb, \u0430\u0432\u0442\u043e\u0440: Jakub Korab, \u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u043e: O&#039;Reilly Media, Inc., \u0434\u0430\u0442\u0430 \u0438\u0437\u0434\u0430\u043d\u0438\u044f: June 2017, ISBN: 9781492049296. \u041f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0430\u044f \u043f\u0435\u0440\u0435\u0432\u0435\u0434\u0435\u043d\u043d\u0430\u044f.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/ponimanie-brokerov-soobshhenij-izuchenie-mehaniki-obmena-soobshheniyami-posredstvom-activemq-i-kafka-glava-3-kafka\" \/>\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:22:05+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T19:22:05+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\udd47Comprendere i broker di messaggi. Studio della meccanica dello scambio di messaggi tramite ActiveMQ e Kafka. Capitolo 3. Kafka | ProHoster","description":"Continuazione della traduzione di un piccolo libro: \"Understanding Message Brokers\", autore: Jakub Korab, editore: O'Reilly Media, Inc., data di pubblicazione: Giugno 2017, ISBN: 9781492049296. Precedente tradotto.","canonical_url":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/ponimanie-brokerov-soobshhenij-izuchenie-mehaniki-obmena-soobshheniyami-posredstvom-activemq-i-kafka-glava-3-kafka","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\u041f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u0431\u0440\u043e\u043a\u0435\u0440\u043e\u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. \u0418\u0437\u0443\u0447\u0435\u043d\u0438\u0435 \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0438 \u043e\u0431\u043c\u0435\u043d\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438 \u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e\u043c ActiveMQ \u0438 Kafka. \u0413\u043b\u0430\u0432\u0430 3. Kafka | ProHoster","og:description":"\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043a\u043d\u0438\u0433\u0438: \u00abUnderstanding Message Brokers\u00bb, \u0430\u0432\u0442\u043e\u0440: Jakub Korab, \u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u043e: O'Reilly Media, Inc., \u0434\u0430\u0442\u0430 \u0438\u0437\u0434\u0430\u043d\u0438\u044f: June 2017, ISBN: 9781492049296. \u041f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0430\u044f \u043f\u0435\u0440\u0435\u0432\u0435\u0434\u0435\u043d\u043d\u0430\u044f.","og:url":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/ponimanie-brokerov-soobshhenij-izuchenie-mehaniki-obmena-soobshheniyami-posredstvom-activemq-i-kafka-glava-3-kafka","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:22:05+00:00","article:modified_time":"2019-10-31T19:22:05+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"38172","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-23 20:46:00","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 15:34:26","updated":"2026-01-23 20:46:00","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/38172","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=38172"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/38172\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media?parent=38172"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/categories?post=38172"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/tags?post=38172"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}