Apache Kafka è una piattaforma di event streaming ad alte prestazioni e altamente scalabile. Per sbloccare il pieno potenziale di Kafka, devi considerare attentamente il design della tua applicazione. È fin troppo facile scrivere applicazioni Kafka che funzionano male o che, alla fine, incontrano un muro di scalabilità. Dal 2015, IBM fornisce il servizio IBM Event Streams, un servizio Apache Kafka completamente gestito che gira su IBM Cloud. Da allora, il servizio ha aiutato molti clienti, così come diversi team all'interno di IBM, a risolvere problemi di scalabilità e prestazioni con le applicazioni Kafka che hanno scritto.
Questo articolo descrive alcuni dei problemi comuni di Apache Kafka e fornisce alcune raccomandazioni su come evitare di incontrare problemi di scalabilità con le tue applicazioni.
Alcune operazioni Kafka funzionano con l'invio dei dati al broker e l'attesa di una risposta. Un intero viaggio di andata e ritorno potrebbe durare 10 millisecondi, il che sembra veloce, ma limita al massimo 100 operazioni al secondo. Per questo motivo, si consiglia di evitare questo tipo di operazioni ogni volta che è possibile. Fortunatamente, i client Kafka offrono la possibilità di evitare di dover attendere i tempi di andata e ritorno. Devi solo assicurarti di sfruttarli al meglio.
Suggerimenti per massimizzare la produttività:
Se hai letto quanto sopra e hai pensato: "Ehi, questo non renderà la mia applicazione più complessa?", la risposta è sì, probabilmente sì. C'è un compromesso tra throughput e complessità dell'applicazione. Ciò che rende il tempo di andata e ritorno della rete una trappola particolarmente insidiosa è che, una volta raggiunto questo limite, possono essere necessarie ampie modifiche alle applicazioni per ottenere ulteriori miglioramenti della produttività.
Una caratteristica utile di Kafka è che monitora la "vitalità" delle applicazioni che consumano e disconnette quelle che potrebbero essere guaste. Funziona facendo in modo che il broker tenga traccia dell'ultima chiamata di ciascun client consumatore tramite "poll" (terminologia di Kafka per richiedere più messaggi). Se un client non esegue il polling con sufficiente frequenza, il broker a cui è connesso conclude che deve essersi verificato un errore e lo disconnette. Ciò è stato progettato per consentire ai clienti che non hanno riscontrato problemi di intervenire e riprendere il lavoro del cliente che ha fallito.
Sfortunatamente, con questo schema il broker Kafka non riesce a distinguere tra un client che impiega molto tempo per elaborare i messaggi ricevuti e un client che in realtà ha fallito. Consideriamo un'applicazione di consumo che esegue un loop: 1) chiama il poll e riceve un batch di messaggi; oppure 2) elabora ogni messaggio del batch, impiegando 1 secondo per elaborare ogni messaggio.
Se questo consumer riceve batch di 10 messaggi, passeranno circa 10 secondi tra le chiamate al polling. Di default, Kafka permette fino a 300 secondi (5 minuti) tra un sondaggio e l'altro prima di disconnettere il client quindi, in questo scenario, tutto funzionerebbe bene. Ma cosa succede in una giornata molto intensa, quando inizia ad accumularsi un arretrato di messaggi sull'argomento che l'applicazione sta consumando? Invece di ricevere solo 10 messaggi di risposta da ogni chiamata, la tua applicazione riceve 500 messaggi (di default questo è il numero massimo di record che può essere restituito tramite una chiamata di poll). Questo comporterebbe abbastanza tempo di elaborazione perché Kafka decida che l'istanza dell'applicazione è fallita e la disconnetta. E questa è una brutta notizia.
Ma ti farà piacere sapere che la situazione può anche peggiorare. È possibile che si verifichi una sorta di ciclo di feedback. Man mano che Kafka inizia a disconnettere i client perché non chiamano i poll abbastanza frequentemente, ci sono meno istanze in cui l'applicazione elabora i messaggi. La probabilità che ci sia un elevato arretrato di messaggi sull'argomento aumenta, con conseguente aumento della probabilità che più clienti ricevano grandi quantità di messaggi e impieghino troppo tempo per elaborarli. Alla fine, tutte le istanze dell'applicazione di consumo entrano in un ciclo di riavvio e non viene svolto alcun lavoro utile.
Quali misure puoi adottare per evitare che ciò accada anche a te?
Torneremo sul tema dei fallimenti dei consumer più avanti in questo articolo, quando vedremo come possono innescare un riequilibrio tra i gruppi di consumer e l'effetto dirompente che ciò può avere.
Dietro le quinte, il protocollo utilizzato dal consumer Kafka per ricevere messaggi funziona inviando una richiesta di “fetch” a un broker Kafka. Come parte di questa richiesta, il client indica cosa deve fare il broker se non ci sono messaggi da restituire, incluso quanto tempo il broker deve attendere prima di inviare una risposta vuota. Per impostazione predefinita, i consumer Kafka indicano ai broker di attendere fino a 500 millisecondi (controllati dalla configurazione del consumer "fetch.max.wait.ms") affinché almeno 1 byte di dati del messaggio diventi disponibile (controllato con la configurazione "fetch.min.bytes").
Attendere 500 millisecondi non sembra irragionevole, ma se la tua applicazione ha consumer per lo più inattivi e si espande fino a 5.000 istanze, significa potenzialmente 2.500 richieste al secondo che non fanno assolutamente nulla. Ognuna di queste richieste richiede tempo di elaborazione da parte del broker e, nei casi più gravi, può avere un impatto negativo sulle prestazioni e sulla stabilità dei client Kafka che desiderano svolgere un lavoro utile.
Normalmente, l'approccio di Kafka alla scalabilità consiste nell'aggiungere altri broker e poi riequilibrare in modo uniforme le partizioni degli argomenti su tutti i broker, sia vecchi che nuovi. Purtroppo, questo approccio potrebbe non aiutare se i tuoi clienti bombardano Kafka con richieste di recupero inutili. Ogni cliente invierà richieste di recupero a tutti i broker che gestiscono una partizione tematica da cui il cliente sta consumando messaggi. Quindi è possibile che anche dopo aver scalato il cluster Kafka e ridistribuito le partizioni, la maggior parte dei tuoi client invierà richieste di fetch alla maggior parte dei broker.
Quindi cosa si può fare?
Se si arriva a Kafka da un background con altri sistemi publish-abbonarsi (ad esempio Message Queuing Telemetry Transport, o MQTT in breve), ci si potrebbe aspettare che gli argomenti di Kafka siano leggeri, quasi effimeri. Non lo sono. Kafka si trova molto più a suo agio con un numero di argomenti nell'ordine delle migliaia. Anche gli argomenti di Kafka sono destinati ad avere una vita relativamente lunga. Pratiche come la creazione di un argomento per ricevere un singolo messaggio di risposta, e poi l'eliminazione dell'argomento, sono poco comuni con Kafka e non sfruttano i suoi punti di forza.
Piuttosto, pianifica argomenti che durino a lungo. Forse condividono la durata di un'applicazione o di un'attività. Cerca anche di limitare il numero di argomenti a centinaia o magari a poche migliaia. Ciò potrebbe richiedere di adottare una prospettiva diversa sui messaggi intervallati da un argomento specifico.
Una domanda correlata che spesso ci si pone è: "Quante partizioni deve avere il mio argomento?" Tradizionalmente, il consiglio è quello di valutare per eccesso, perché aggiungere partizioni dopo la creazione di un argomento non cambia il partizionamento dei dati esistenti sull'argomento (e quindi può influenzare i consumer che si affidano al partizionamento per offrire l'ordinamento dei messaggi all'interno di una partizione). Questo è un buon consiglio. Tuttavia, vorremmo suggerire alcune considerazioni aggiuntive:
La maggior parte delle applicazioni Kafka che consumano messaggi utilizza al meglio le funzionalità di Kafka per i gruppi di consumer per coordinare quali client consumano da quali partizioni di argomento. Se il tuo ricordo dei gruppi di consumer è un po' confuso, ecco un rapido riepilogo dei punti chiave:
Con la maturazione di Kafka, sono stati (e continuano ad essere) ideati algoritmi di ribilanciamento sempre più sofisticati. Nelle prime versioni di Kafka, quando un gruppo di consumer veniva ribilanciato, tutti i client del gruppo dovevano smettere di consumare, le partizioni degli argomenti venivano ridistribuite tra i nuovi membri del gruppo e tutti i client ricominciavano a consumare. Questo approccio presenta due svantaggi (che nel frattempo sono stati migliorati):
Gli algoritmi di ribilanciamento più recenti hanno apportato miglioramenti significativi, aggiungendo, per usare la terminologia di Kafka, "viscosità" e "cooperazione":
Nonostante questi miglioramenti agli algoritmi di ribilanciamento più recenti, se le tue applicazioni sono frequentemente soggette a ribilanciamenti dei gruppi di consumer, vedrai comunque un impatto sulla velocità complessiva dei messaggi e sprecherai banda di rete mentre i client scartano e recuperano i dati dei messaggi in buffer. Ecco alcuni suggerimenti su cosa puoi fare:
Newsletter di settore
Resta al passo con le tendenze più importanti e interessanti del settore relative ad AI, automazione, dati e oltre con la newsletter Think. Leggi l' Informativa sulla privacy IBM.
L'abbonamento sarà fornito in lingua inglese. Troverai un link per annullare l'iscrizione in tutte le newsletter. Puoi gestire i tuoi abbonamenti o annullarli qui. Per ulteriori informazioni, consulta l'Informativa sulla privacy IBM.
Ora sei un esperto nella scalabilità delle applicazioni Kafka. Sei invitato a mettere in pratica questi punti e provare l'offerta completamente gestita di Kafka su IBM Cloud. Per qualsiasi problema di configurazione, consulti la Guida introduttiva e le FAQ.
IBM Event Streams è un software per lo streaming di eventi basato sull'open source Apache Kafka. È disponibile come servizio totalmente gestito su IBM Cloud o in self-hosting.
Sblocca il potenziale aziendale con le soluzioni di integrazione di IBM, collegando applicazioni e sistemi per accedere rapidamente e in modo sicuro ai dati d'importanza critica.
Sblocca nuove funzionalità e promuovi l'agilità aziendale con i servizi di consulenza cloud di IBM.