Come posso inviare messaggi di grandi dimensioni con Kafka (oltre 15 MB)?


118

Invio di messaggi String a Kafka V. 0.8 con l'API Java Producer. Se la dimensione del messaggio è di circa 15 MB, ottengo un file MessageSizeTooLargeException. Ho provato a impostare message.max.bytessu 40 MB, ma ottengo ancora l'eccezione. I piccoli messaggi funzionavano senza problemi.

(L'eccezione appare nel produttore, non ho un consumatore in questa applicazione.)

Cosa posso fare per sbarazzarmi di questa eccezione?

Il mio esempio di configurazione del produttore

private ProducerConfig kafkaConfig() {
    Properties props = new Properties();
    props.put("metadata.broker.list", BROKERS);
    props.put("serializer.class", "kafka.serializer.StringEncoder");
    props.put("request.required.acks", "1");
    props.put("message.max.bytes", "" + 1024 * 1024 * 40);
    return new ProducerConfig(props);
}

Error-Log:

4709 [main] WARN  kafka.producer.async.DefaultEventHandler  - Produce request with correlation id 214 failed due to [datasift,0]: kafka.common.MessageSizeTooLargeException
4869 [main] WARN  kafka.producer.async.DefaultEventHandler  - Produce request with    correlation id 217 failed due to [datasift,0]: kafka.common.MessageSizeTooLargeException
5035 [main] WARN  kafka.producer.async.DefaultEventHandler  - Produce request with   correlation id 220 failed due to [datasift,0]: kafka.common.MessageSizeTooLargeException
5198 [main] WARN  kafka.producer.async.DefaultEventHandler  - Produce request with correlation id 223 failed due to [datasift,0]: kafka.common.MessageSizeTooLargeException
5305 [main] ERROR kafka.producer.async.DefaultEventHandler  - Failed to send requests for topics datasift with correlation ids in [213,224]

kafka.common.FailedToSendMessageException: Failed to send messages after 3 tries.
at kafka.producer.async.DefaultEventHandler.handle(Unknown Source)
at kafka.producer.Producer.send(Unknown Source)
at kafka.javaapi.producer.Producer.send(Unknown Source)

5
Il mio primo istinto sarebbe chiederti di dividere questo enorme messaggio in più messaggi più piccoli: - / La mia ipotesi è che questo non sia possibile per qualche motivo, ma potresti volerlo riconsiderare comunque: messaggi enormi di solito indicano che c'è un difetto di progettazione da qualche parte che dovrebbe davvero essere risolto.
Aaron Digulla

1
Grazie, ma renderebbe la mia logica molto più complessa. Perché è una cattiva idea usare Kafka per messaggi di circa 15 MB? 1 MB è il limite massimo di dimensioni dei messaggi che è possibile utilizzare? Non ho trovato molto sul limite di dimensione dei messaggi nella documentazione di Kafka.
Sonson123

2
Questo è completamente estraneo a Kafka o qualsiasi altro sistema di elaborazione dei messaggi. Il mio ragionamento: se qualcosa va storto con il tuo file da 15 MB, ripulire il disordine in seguito è molto costoso. Ecco perché di solito divido file di grandi dimensioni in molti lavori più piccoli (che di solito possono essere eseguiti anche in parallelo).
Aaron Digulla

hai usato qualche compressione? potresti per favore condividere qualche dettaglio in più, è piuttosto difficile indovinare qualcosa da una sola parola
user2720864

Risposte:


181

È necessario regolare tre (o quattro) proprietà:

  • Lato consumatore: fetch.message.max.bytesdeterminerà la dimensione massima di un messaggio che può essere recuperata dal consumatore.
  • Lato broker: replica.fetch.max.bytesquesto consentirà alle repliche nei broker di inviare messaggi all'interno del cluster e di assicurarsi che i messaggi vengano replicati correttamente. Se è troppo piccolo, il messaggio non verrà mai replicato e, di conseguenza, il consumatore non vedrà mai il messaggio perché il messaggio non verrà mai sottoposto a commit (replicato completamente).
  • Lato broker: message.max.bytes- questa è la dimensione massima del messaggio che può essere ricevuto dal broker da un produttore.
  • Lato broker (per argomento): max.message.bytesquesta è la dimensione massima del messaggio che il broker consentirà di aggiungere all'argomento. Questa dimensione è convalidata prima della compressione. (L'impostazione predefinita è quella del broker message.max.bytes.)

Ho scoperto a mie spese il numero 2: non ricevi ALCUNA eccezione, messaggio o avviso da Kafka, quindi assicurati di tenerlo in considerazione quando invii messaggi di grandi dimensioni.


3
Ok, tu e l'utente2720864 avevate ragione. Avevo impostato solo message.max.bytesnel codice sorgente. Ma devo impostare questi valori nella configurazione del server Kafka config/server.properties. Ora funzionano anche i messaggi più grandi :).
Sonson123

3
Ci sono svantaggi noti impostando questi valori troppo alti?
Ivan Balashov

7
Sì. Dal lato del consumatore, si alloca la fetch.message.max.bytesmemoria per OGNI partizione. Ciò significa che se si utilizza un numero enorme per fetch.message.max.bytescombinato con un numero elevato di partizioni, consumerà molta memoria. Infatti, poiché il processo di replica tra i broker è anche un consumatore specializzato, questo consumerà memoria anche sui broker.
laughing_man

3
Nota che esiste anche una max.message.bytesconfigurazione per argomento che può essere inferiore a quella del broker message.max.bytes.
Peter Davis

1
Secondo il documento ufficiale, i parametri lato consumatore e quelli riguardanti la replica tra broker /.*fetch.*bytes/non sembrano essere limiti rigidi: "Questo non è un massimo assoluto, se [...] maggiore di questo valore, il record batch sarà essere restituiti per garantire che si possano compiere progressi ".
Bluu

56

Piccole modifiche richieste per Kafka 0.10 e il nuovo consumatore rispetto alla risposta di laughing_man :

  • Broker: Nessuna modifica, è comunque necessario aumentare le proprietà message.max.bytese replica.fetch.max.bytes. message.max.bytesdeve essere uguale o minore (*) di replica.fetch.max.bytes.
  • Produttore: aumentare max.request.sizeper inviare il messaggio più grande.
  • Consumatore: aumentare max.partition.fetch.bytesper ricevere messaggi più grandi.

(*) Leggi i commenti per saperne di più su message.max.bytes<=replica.fetch.max.bytes


2
Sai perché message.max.bytesdeve essere più piccolo di replica.fetch.max.bytes?
Kostas

2
" replica.fetch.max.bytes (impostazione predefinita: 1 MB): dimensione massima dei dati che un broker può replicare. Deve essere maggiore di message.max.bytes , altrimenti un broker accetterà i messaggi e non riuscirà a replicarli. potenziale perdita di dati. " Fonte: handling-large-messages-kafka
Sascha Vetter

2
Grazie per avermi contattato con un link. Questo sembra riecheggiare ciò che suggerisce anche la guida di Cloudera . Entrambi però sono sbagliati: si noti che non offrono alcuna ragione tecnica sul perché replica.fetch.max.bytes dovrebbe essere strettamente maggiore di message.max.bytes. Un dipendente Confluent ha confermato oggi quello che sospettavo: che le due quantità possono, infatti, essere uguali.
Kostas

2
Ci sono aggiornamenti riguardanti message.max.bytes<replica.fetch.max.byteso message.max.bytes=replica.fetch.max.bytes@Kostas?
Sascha Vetter

2
Sì, possono essere uguali: mail-archive.com/users@kafka.apache.org/msg25494.html (Ismael lavora per Confluent)
Kostas

13

È necessario sovrascrivere le seguenti proprietà:

Configurazioni broker ($ KAFKA_HOME / config / server.properties)

  • replica.fetch.max.bytes
  • message.max.bytes

Consumer Configs ($ KAFKA_HOME / config / consumer.properties)
Questo passaggio non ha funzionato per me. L'ho aggiunto all'app consumer e funzionava bene

  • fetch.message.max.bytes

Riavvia il server.

guarda questa documentazione per maggiori informazioni: http://kafka.apache.org/08/configuration.html


1
per il consumatore da riga di comando, ho bisogno di usare il flag --fetch-size = <bytes>. Non sembra leggere il file consumer.properties (kafka 0.8.1). Suggerirei anche di attivare la compressione dal lato produttore usando l'opzione compression.codec.
Ziggy Eunicien

Il commento di Ziggy ha funzionato per me kafka 0.8.1.1. Grazie!
James

potrebbe essere che fetch.message.max.bytes sia sostituito da max.partition.fetch.bytes in ConsumerConfig?
s_bei

12

L'idea è di avere la stessa dimensione del messaggio inviato da Kafka Producer a Kafka Broker e quindi ricevuto da Kafka Consumer, ovvero

Produttore Kafka -> Broker Kafka -> Consumatore Kafka

Supponiamo che se il requisito è di inviare 15 MB di messaggio, il produttore , il broker e il consumatore , tutti e tre, devono essere sincronizzati.

Kafka Producer invia 15 MB -> Kafka Broker consente / archivia 15 MB -> Kafka Consumer riceve 15 MB

L'impostazione quindi dovrebbe essere:

a) su Broker:

message.max.bytes=15728640 
replica.fetch.max.bytes=15728640

b) sul consumatore:

fetch.message.max.bytes=15728640

2
potrebbe essere che fetch.message.max.bytes sia sostituito da max.partition.fetch.bytes in ConsumerConfig?
s_bei

7

Una cosa fondamentale da ricordare che l' message.max.bytesattributo deve essere sincronizzato con la fetch.message.max.bytesproprietà del consumatore . la dimensione del fetch deve essere grande almeno quanto la dimensione massima del messaggio altrimenti potrebbe esserci una situazione in cui i produttori possono inviare messaggi più grandi di quanto il consumatore possa consumare / fetch. Potrebbe valere la pena dargli un'occhiata.
Quale versione di Kafka stai usando? Fornisci anche qualche traccia di dettagli in più che stai ottenendo. c'è qualcosa come ... in payload size of xxxx larger than 1000000arrivo nel registro?


1
Ho aggiornato la mia domanda con ulteriori informazioni: Kafka Version 2.8.0-0.8.0; ora mi serve solo il produttore.
Sonson123

6

La risposta di @laughing_man è abbastanza accurata. Tuttavia, volevo dare una raccomandazione che ho imparato dall'esperto di Kafka Stephane Maarek di Quora.

Kafka non è pensato per gestire messaggi di grandi dimensioni.

La tua API dovrebbe utilizzare l'archiviazione cloud (Ex AWS S3) e inviare semplicemente a Kafka oa qualsiasi broker di messaggi un riferimento di S3. Devi trovare un posto in cui conservare i tuoi dati, forse è un'unità di rete, forse è qualunque cosa, ma non dovrebbe essere un broker di messaggi.

Ora, se non vuoi andare con la soluzione sopra

La dimensione massima del messaggio è 1 MB (l'impostazione nei broker è chiamata message.max.bytes) Apache Kafka . Se ne avevi davvero bisogno, potresti aumentare quella dimensione e assicurarti di aumentare i buffer di rete per i tuoi produttori e consumatori.

E se ti interessa davvero dividere il tuo messaggio, assicurati che ogni divisione del messaggio abbia la stessa identica chiave in modo che venga inviata alla stessa partizione e il contenuto del tuo messaggio dovrebbe riportare un "ID parte" in modo che il tuo consumatore possa ricostruire completamente il messaggio .

Puoi anche esplorare la compressione, se il tuo messaggio è basato su testo (compressione gzip, snappy, lz4) che può ridurre la dimensione dei dati, ma non magicamente.

Di nuovo, devi usare un sistema esterno per archiviare quei dati e semplicemente inviare un riferimento esterno a Kafka. Questa è un'architettura molto comune e dovresti andare con e ampiamente accettata.

Tieni presente che Kafka funziona meglio solo se i messaggi sono enormi in quantità ma non in dimensioni.

Fonte: https://www.quora.com/How-do-I-send-Large-messages-80-MB-in-Kafka



Kafka funziona con messaggi di grandi dimensioni, assolutamente nessun problema. La pagina introduttiva sulla home page di Kafka fa riferimento anche a un sistema di archiviazione.
calloc_org

3

Per le persone che usano landoop kafka: puoi passare i valori di configurazione nelle variabili d'ambiente come:

docker run -d --rm -p 2181:2181 -p 3030:3030 -p 8081-8083:8081-8083  -p 9581-9585:9581-9585 -p 9092:9092
 -e KAFKA_TOPIC_MAX_MESSAGE_BYTES=15728640 -e KAFKA_REPLICA_FETCH_MAX_BYTES=15728640  landoop/fast-data-dev:latest `

E se stai usando rdkafka, passa il messaggio message.max.bytes nella configurazione del produttore come:

  const producer = new Kafka.Producer({
        'metadata.broker.list': 'localhost:9092',
        'message.max.bytes': '15728640',
        'dr_cb': true
    });

Allo stesso modo, per il consumatore,

  const kafkaConf = {
   "group.id": "librd-test",
   "fetch.message.max.bytes":"15728640",
   ... .. }                                                                                                                                                                                                                                                      
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.