Differenze tra JMS e KAFKA

E’ da qualche tempo che senti parlare di Apache Kafka (piattaforma di stream-processing distribuita) ma hai sempre sviluppato applicazioni utilizzando JMS di IBM?

Apache Kafka è tra i più popolari sistemi di messaggistica istantanea gratuiti (open source) utilizzato al mondo. Ha molte funzionalità che lo rendono appetibile in alcune situazioni. In questo articolo andremo a vedere quali sono queste situazioni e, senza parlare dei punti di incontro, analizzeremo le differenze che ci sono tra JMS e KAFKA.

Prima di vedere le differenze tra JMS e KAFKA facciamo una breve panoramica del secondo motore di messaggistica istantanea.

Parliamo di KAFKA

KAFKA, tanto per ripeterci, è un motore di messaggistica istantanea nato da zero, studiato per ottenere il massimo delle prestazioni, alta scalabilità e soprattutto una continuità nell’erogazione del servizio. Permette di gestire in tempo reale migliaia di client in lettura e scrittura.

Kafka nasce nel 2010 grazie a linkedin che in una fase di crescita ha sentito l’esigenza di affrontare in modo concreto il problema della bassa latenza inerenti all’erogazione e gestione di una quantità di dati elevata sul web. Non avendo a disposizione una soluzione che potesse soddisfare questa esigenza decise di dare forma ad una nuova piattaforma che potesse soddisfare questa esigenza. Le soluzioni batch adottate fino a quel momento non appagavano l’esigenza di elaborare e gestire i dati in tempo reale. L’esigenza principale era di poter elaborare velocemente una grande mole di dati e di farlo in tempo reale.

Le basi di KAFKA

Vediamo insieme quali sono le basi di questo potente motore di messaggistica. Per poter apprendere meglio il funzionamento e l’utilizzo di questo potente motore di messaggistica istantanea è importante conoscere JAVA, Scala e linux.

  • Producers sono coloro che pubblicano gli argomenti;
  • consumers sono gli utenti che si iscrivono ai topics;
  • messages sono i messaggi che vengono inviati in array di byte, JSON object, stringhe etc…;
  • topics possiamo definirla una sorta di “tipologia” che raggruppa i messaggi;
  • partizione: ciascuna delle sottosezioni in cui è diviso un topic;
  • record è il messaggio vero e proprio, costituito da una chiave, un valore e un timestamp;
  • connector strumento che consente il collegamento tra le varie piattaforme e applicazioni;
  • broker è un processo che si occupa di gestire la ricezione e il salvataggio dei messaggi e i relativi offset.

Di seguito vediamo nella figura un esempio di erogazione di un messaggio in un “topic” con N partizioni.

KAFKA - esempio di topic suddiviso in partizioni

KAFKA – esempio di topic suddiviso in partizioni

KAFKA – esempio di topic suddiviso in partizioni

Parliamo di Topic e Partizioni

Come notiamo nella figura sopra ogni Partizione contiene N numeri di Records con un suo offset. Di seguito vediamo come è definita una partizione a cui il messaggio viene affidato. Possiamo definire che la partizione è:

  • scelta dal Producer nel momento in cui viene affidato il messaggio;
  • qualora fosse presente è ottenuta elaborando l’hash della chiave del record;
  • se il Producer non ha indicato né una partizione né una chiave per il messaggio una qualsiasi secondo una logica di tipo round-robin.

JMS Versus Kafka – Quali sono le differenze tra questi motori di messaggistica?

Non ci sono concetti di coda ma…

Quando parliamo di KAFKA dimentichiamoci per un momento del concetto di “Coda”. L’unico vero paradigma di Kafka è “Pubblica/Iscriviti”. Il Producer pubblica un argomento in un TOPIC e i consumers, iscritti a quel TOPIC, ricevono il messaggio. Questo concetto è molto simile al funzionamento di JMS, la differenza sostanziale è nelle “Cover” che vedremo più avanti.

Diamo una occhiata alle differenze tra JMS e KAFKA.

Persistenza del messaggio

Diciamo subito che Kafka conserva i messaggi anche dopo che tutti gli abbonati hanno letto il messaggio. Il periodo di noleggio è un parametro configurabile. La differenza tra gli altri provider JMS tipici (IBM MQ, Rabbit MQ, Active MQ ..) è che questi implementano gli argomenti in modo tale che i messaggi pubblicati sull’argomento vengano inviati a un archivio comune (memoria o / e archivio persistente) da dove vengono raccolti da gli abbonati ai topic. Nei sistemi MQ / JMS una volta letto, il messaggio viene rimosso dalla memoria e non è più disponibile.

In una tipica implementazione consumer JMS, il messaggio viene eliminato dal sistema di messaggistica alla ricezione di un ACK / Commit. Se per qualche motivo il messaggio viene elaborato ma non riesce prima dell’ACK / Commit, il messaggio verrebbe letto più di una volta. Questo problema è stato risolto da Kafka attraverso la conservazione dei messaggi e la gestione dello stato basata sull’offset del consumatore.

KAFKA la partizione dei Topic (argomenti)

Kafka implementa gli argomenti come registri partizionati (vedi figura sopra). Una partizione è una sequenza ordinata e immutabile di messaggi che viene continuamente aggiunta. Questa funzionalità è molto simile al registro del database, per questo motivo la partizione viene anche definita commit-log. Questa è una delle maggiori differenze tra JMS e Kafka. Il partizionamento dell’argomento porta al suo elevato throughput (e parallelismo). Una maggiore velocità nel distribuire il messaggio nel topic e verso i Consumers.

Anatomia di un TOPIC

Anatomia di un TOPIC

Anatomia di un TOPIC

Sequenza dei messaggi

Quando utiliziamo JMS non abbiamo alcuna garanzia che i messaggi saranno ricevuti nella sequenza in cui sono stati realmente “accodati” e inviati dal Producer. Nel motore di messaggistica istantanea Kafka, proprio nella logica delle partizioni, la sequenza è mantenuta . In altre parole, se l’argomento è configurato con una singola partizione, i messaggi vengono ricevuti dai Consumers nello stesso ordine in cui sono stati inviati dal Producer.

Lettura del messaggio

Il consumatore dei messaggi (Consumer) in Kafka inoltra una richiesta di recupero al broker. E’ il broker che guida la partizione che desidera utilizzare. Come parte del recupero, il consumatore specifica l’offset da cui viene letto il messaggio nel registro. Questo è molto diverso dal sistema di messaggistica JMS in cui la logica di First In First Out (FIFO) è utilizzata per leggere i messaggi dalla coda/argomento. Il primo che entra viene letto. L’altra cosa che succede è che con il controllo basato sull’offset, il consumatore può rileggere lo stesso messaggio più volte cosa che non accade, in questo specifico modo come ho già detto prima, nelle code JMS.

Questo meccanismo di riavvolgimento può essere molto utile in alcune situazioni. Ad esempio, se hai ricevuto un batch di messaggi e lo hai elaborato con un codice errato, puoi correggere il codice ed eseguire nuovamente l’elaborazione sui messaggi ripristinando l’offset.

Bilanciamento del carico

Nel caso del motore di messaggistica istantanea JMS il bilanciamento del carico richiede che i sistemi fossero progettati utilizzando un meccanismo di clustering e l’onere della distribuzione del carico tra i membri del cluster è demandata al Producer che inviava i messaggi. I nodi Kafka pubblicano i metadati che indicano al Producer quali server sono attivi nel cluster e dove si trovano i leader delle partizioni. Ciò consente al client di inviare un messaggio al server (e alla partizione) appropriato, distribuendo così il carico del messaggio tra i membri del cluster.

Failover automatico e alta disponibilità del servizio

Le implementazioni JMS tradizionali non avevano il concetto di replica dei messaggi ma alcuni sistemi, in un periodo di tempo limitato, lo hanno costruito. La funzionalità di replica, nella maggior parte dei casi, non sono state studiate a favore della semplicità. In Kafka i messaggi vengono replicati (leader-follower) tra le partizioni di ciascun argomento su un numero configurabile di N server. Questo porta intrinsecamente ad un’architettura che fornisce e garantisce il failover automatico e una elevata disponibilità del servizio.

Installiamo KAFKA

Vediamo ora come installare KAFKA. Per renderci la vita meno difficile vi consiglio di installare KAFKA con un’immagine Docker. Prima di farlo ricordiamoci di installare ZooKeeper.

Zookeeper svolge un ruolo centrale anche nel meccanismo di replica. I server follower mantengono una sessione per zookeeper e rispondono ai messaggi heartbeat. Gli slaves/replicas leggono continuamente i messaggi dal leader il più velocemente possibile per non restare indietro. Il leader se scopre che lo slave è in ritardo lo rimuove come replica; questo è determinato mediante parametri configurabili. Il messaggio viene considerato impegnato quando tutte le repliche sono sincronizzate con il leader. Anche questo aspetto della sincronizzazione è configurabile.

Quindi è corretto dire che Zookeeper si occuperà della sincronizzazione dei sistemi di replica distribuiti.

Di seguito è riportato un esempio di docker-compose.yml che permette di avviare entrambi i servizi.

version: '2'
services:
       zookeeper:
       image: wurstmeister/zookeeper
       ports:
              - 2181:2181
       kafka:
       image: wurstmeister/kafka
       ports:
              - 9092:9092
       depends_on:
              - zookeeper
       environment:
              KAFKA_LISTENERS: PLAINTEXT://:9092
              KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
              KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
              KAFKA_CREATE_TOPICS: "Stocks:2:1,Quotes:2:1,Orders:2:1"

Come si nota, nel file è stata valorizzata anche la variabile d’ambiente KAFKA_CREATE_TOPICS. Questo permette di creare automaticamente un insieme di topic specificandone il nome, nonché il numero di partizioni e di repliche necessarie per far funzionare il sistema.

Nel prossimo articolo andremo a vedere un esempio di programma per implementare KAFKA in JAVA.

Potrebbero interessarti anche...