Vai al contenuto
English

Blog · Ricerca

Cercare un valore in milioni di messaggi Kafka: quanto ci vuole davvero

· 3 min di lettura · Claudio Dall'Ara

«Mi trovi l'ordine del cliente RSSMRA80A01H501U?» In un database è una query con un indice. In Apache Kafka no: un topic è un log, e il broker non sa cosa c'è dentro i messaggi. Per trovare un valore dentro un JSON qualcuno deve leggere i messaggi e guardarci dentro.

Quanto ci vuole? Meno di quanto si teme, se si fanno i conti giusti.

Contano i byte, non i messaggi

La tentazione è ragionare in numero di messaggi. Ma il lavoro vero è scaricare i byte dal broker al tuo PC. Il controllo del testo, per un programma scritto bene, costa poco.

Un modello semplice regge sorprendentemente bene:

tempo ≈ il più lungo fra (byte da scaricare ÷ banda) e (messaggi ÷ messaggi al secondo che il programma sa controllare)

Con messaggi di qualche centinaio di byte vince quasi sempre la banda. Qualche ordine di grandezza, per topic non compressi e messaggi da 500 byte:

MessaggiDatiRete da circa 35 MB/sRete da 1 Gbit
1 milione0,5 GBcirca 14 scirca 4 s
10 milioni5 GBcirca 2 mincirca 43 s
50 milioni25 GBcirca 11 mincirca 4 min

Sono stime, non promesse: rete, broker e dischi cambiano tutto. Ma danno l'ordine di grandezza giusto, e soprattutto si possono calcolare prima di partire, dal numero di messaggi (fine meno inizio di ogni partizione) e da un piccolo campione per il peso medio.

Una misura reale per confronto: 12 milioni di JSON da circa 500 byte, 5,8 GB non compressi, letti per intero in 2 minuti e 2 secondi su un Redpanda locale in Docker, con il motore di ricerca che non ha mai superato i 30 MB di RAM.

La compressione aiuta

Se il topic è compresso con lz4 o zstd, dalla rete passano meno byte e il tempo spesso si dimezza. Il costo di decomprimere è piccolo rispetto alla rete. Se cerchi spesso negli stessi topic, chiedi a chi li produce se la compressione è attiva: è un'impostazione del produttore, compression.type.

Tre modi per leggere meno

1. Per chiave: una partizione sola

Se il valore che cerchi è la chiave del messaggio, non serve leggere tutto il topic. La chiave decide la partizione: basta ricalcolarla e leggere solo quella. Su un topic da 12 partizioni, circa 12 volte meno dati.

Attenzione al dettaglio che fa sbagliare: il partizionatore non è uguale dappertutto. Il produttore Java usa murmur2 sui byte della chiave. librdkafka, di default, usa CRC32 (consistent_random). Se ricalcoli con quello sbagliato, cerchi nella partizione sbagliata e trovi zero. Un buon strumento prova tutti e due, o ti lascia scegliere.

E se le partizioni sono state assegnate a mano dal produttore, la chiave non dice nulla: lì serve la ricerca su tutto il topic.

2. Per periodo: dagli offset al tempo

Se sai che l'ordine è di ieri, non serve leggere un mese. Kafka sa tradurre un istante in un offset: la richiesta ListOffsets con un timestamp (nel client Java offsetsForTimes) restituisce, per ogni partizione, il primo offset con un timestamp uguale o successivo. Si fa per l'inizio e per la fine del periodo, e si legge solo quello che sta in mezzo.

3. Fermarsi presto

Se ti basta sapere che il valore c'è, fermati al primo risultato. Se ne vuoi i primi cento, fermati a cento. Sembra ovvio, ma molti strumenti leggono comunque tutto.

Quello che conviene pretendere da uno strumento

  • La stima prima di partire, così decidi se restringere il periodo.
  • Il tempo rimasto durante, che si corregge con la velocità vera.
  • Il conteggio di tutti i risultati, anche se ne tiene in memoria solo i primi mille.
  • Memoria ferma: leggere 10 milioni di messaggi non deve voler dire tenerli tutti in RAM.
  • Un limite di velocità, quando cerchi su un cluster di produzione e non vuoi pesare sui broker.