Blog · Ricerca
Cercare un valore in milioni di messaggi Kafka: quanto ci vuole davvero
«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:
| Messaggi | Dati | Rete da circa 35 MB/s | Rete da 1 Gbit |
|---|---|---|---|
| 1 milione | 0,5 GB | circa 14 s | circa 4 s |
| 10 milioni | 5 GB | circa 2 min | circa 43 s |
| 50 milioni | 25 GB | circa 11 min | circa 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.