如何使用Kafka(超过15MB)发送大量邮件?

时间:2014-01-09 12:31:33

标签: java apache-kafka

我使用Java Producer API向Kafka V. 0.8发送String-messages。 如果邮件大小约为15 MB,我会得到MessageSizeTooLargeException。 我试图将message.max.bytes设置为40 MB,但我仍然得到例外。小消息没有问题。

(生成器中出现异常,我在此应用程序中没有使用者。)

我可以做些什么来摆脱这种异常?

我的示例生成器配置

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);
}

错误日志:

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)

9 个答案:

答案 0 :(得分:139)

您需要调整三个(或四个)属性:

  • 消费者方:fetch.message.max.bytes - 这将确定消费者可以获取的消息的最大大小。
  • 代理方:replica.fetch.max.bytes - 这将允许代理中的副本在群集内发送消息,并确保正确复制消息。如果这个太小,则永远不会复制该消息,因此,消费者永远不会看到该消息,因为该消息永远不会被提交(完全复制)。
  • 经纪人方:message.max.bytes - 这是经纪人从制作人处收到的最大邮件大小。
  • 代理方(每个主题):max.message.bytes - 这是代理允许附加到主题的消息的最大大小。此大小经过预压缩验证。 (默认为经纪人的message.max.bytes。)

我发现了关于2号的困难方法 - 你没有从Kafka那里得到任何例外,消息或警告,所以在你发送大量消息时一定要考虑这个。

答案 1 :(得分:42)

Kafka 0.10 new consumerlaughing_man's answer相比需要进行细微更改:

  • 代理:无需更改,您仍需要增加属性message.max.bytesreplica.fetch.max.bytesmessage.max.bytes必须等于或小于(*)而不是replica.fetch.max.bytes
  • 制片人:增加max.request.size以发送更大的讯息。
  • 消费者:增加max.partition.fetch.bytes以接收更大的消息。

(*)阅读评论,详细了解message.max.bytes< = replica.fetch.max.bytes

答案 2 :(得分:11)

您需要覆盖以下属性:

经纪人配置($ KAFKA_HOME / config / server.properties)

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

消费者配置($ KAFKA_HOME / config / consumer.properties)
此步骤对我不起作用。我将它添加到消费者应用程序,它工作正常

  • fetch.message.max.bytes

重启服务器。

查看此文档以获取更多信息: http://kafka.apache.org/08/configuration.html

答案 3 :(得分:8)

我们的想法是将相同大小的信息从Kafka Producer发送给Kafka Broker,然后由Kafka Consumer收到,即

Kafka制片人 - > Kafka Broker - >卡夫卡消费者

假设要求是发送15MB的消息,那么生产者,经纪人和消费者这三者都需要同步。

Kafka Producer 发送15 MB - > Kafka Broker 允许/存储15 MB - > Kafka Consumer 获得15 MB

因此应该设置 A.)关于经纪人: message.max.bytes = 15728640 replica.fetch.max.bytes = 15728640

B。)关于消费者: fetch.message.max.bytes = 15728640

答案 4 :(得分:6)

要记住,message.max.bytes属性必须同步与消费者的fetch.message.max.bytes属性有关。获取大小必须至少与最大消息大小一样大,否则可能存在生成器可以发送大于消费者可以使用/获取的消息的情况。值得一看的是它。
您使用的是哪个版本的Kafka?还提供了一些您将获得的更多详细信息跟踪。有没有像payload size of xxxx larger than 1000000出现在日志中的东西?

答案 5 :(得分:4)

@laughing_man的回答非常准确。但我仍然想提出建议,这是我从Quora的Kafka专家 Stephane Maarek 那里学到的。

Kafka并不是要处理大型邮件。

您的API应该使用云存储(Ex AWS S3),并且只需向Kafka或任何消息代理推送S3的引用即可。您必须找到某个地方来保存数据,也许是网络驱动器,也许是任何东西,但不应该是消息代理。

现在,如果您不想采用上述解决方案

消息的最大大小为1MB(您的代理中的设置称为message.max.bytesApache Kafka。如果真的很需要它,则可以增加该大小,并确保为生产者和消费者增加网络缓冲区。

如果您真的很想拆分邮件,请确保每个邮件拆分都具有完全相同的密钥,以便将其推送到同一分区,并且邮件内容应报告“部件ID”,以便您的使用者可以完全重建消息。

如果您的消息是基于文本的(gzip,snappy,lz4压缩),则还可以探索压缩,这可能会减小数据大小,但并非不可思议。

同样,您必须使用外部系统来存储该数据,并且只需将外部引用推送到Kafka。这是一种非常常见的体系结构,您应该使用并被广泛接受的体系结构。

请记住,仅当邮件数量巨大但大小不够时,Kafka才能发挥最佳作用。

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

答案 6 :(得分:3)

对于使用Landoop Kafka的用户: 您可以在环境变量中传递配置值,例如:

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 `

如果您使用rdkafka,则在生产者配置中传递message.max.bytes,例如:

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

类似地,对于消费者

  const kafkaConf = {
   "group.id": "librd-test",
   "fetch.message.max.bytes":"15728640",
   ... .. }                                                                                                                                                                                                                                                      

答案 7 :(得分:2)

我认为,这里的大多数答案都有些过时或不完整。

要参考 answer of Sacha Vetter(带有 Kafka 0.10 的更新),我想提供一些额外的信息和官方文档的链接。


生产者配置:

代理/主题配置:

  • message.max.bytes (Link) 可以设置,如果想在代理级别增加消息大小。但是,来自文档:“这可以使用主题级别 max.message.bytes 配置为每个主题设置。”
  • max.message.bytes (Link) 可能会增加,如果只有一个主题应该能够接受更大的文件。不得更改代理配置。

我总是更喜欢主题限制配置,因为我可以自己将主题配置为 Kafka 集群的客户端(例如使用 admin client)。我可能对代理配置本身没有任何影响。


在上面的答案中,还提到了一些必要的配置:

来自文档:"这不是绝对最大值,如果fetch的第一个非空分区中的第一批记录批大于此值,仍会返回记录批以确保进度可以制作。”

来自文档:“记录是由消费者分批获取的。如果获取的第一个非空分区中的第一个记录批次大于此限制,则仍将返回该批次以确保消费者可以取得进步。”

来自文档:“记录是由消费者分批获取的,如果获取的第一个非空分区中的第一个记录批处理大于此值,则记录批处理仍将返回给确保消费者能够取得进步。”


结论:关于获取消息的配置不需要更改以处理消息,大于这些配置的默认值(在小型设置中测试过)。可能,消费者可能总是得到大小为 1 的批次。但是,必须设置第一个块中的两个配置,如之前的答案所述。

此说明不应说明任何有关性能的信息,也不应建议设置或不设置这些配置。必须根据具体的计划吞吐量和数据结构单独评估最佳值。

答案 8 :(得分:0)

以下是我使用 kafka-python==2.0.2 成功发送高达 100mb 的数据的方法:

经纪人:

consumer = KafkaConsumer(
    ...
    max_partition_fetch_bytes=max_bytes,
    fetch_max_bytes=max_bytes,         
)

Producer(见文末最终解决方案):

producer = KafkaProducer(
    ...
    max_request_size=KafkaSettings.MAX_BYTES,
)

那么:

producer.send(topic, value=data).get()

像这样发送数据后,出现如下异常:

MessageSizeTooLargeError: The message is n bytes when serialized which is larger than the total memory buffer you have configured with the buffer_memory configuration.

最后我增加了 buffer_memory(默认 32mb)以在另一端接收消息。

producer = KafkaProducer(
    ...
    max_request_size=KafkaSettings.MAX_BYTES,
    buffer_memory=KafkaSettings.MAX_BYTES * 3,
)