如何有效地将消息从Seq [String]发送到Kafka主题

时间:2019-10-16 19:42:35

标签: multithreading scala apache-kafka kafka-producer-api

在我的Scala(2.11)流应用程序中,我正在使用IBM MQ中一个队列中的数据,并将其写入具有一个分区的Kafka主题。在使用了来自MQ的数据之后,消息有效负载被拆分为3000个较小的消息,这些消息存储在字符串序列中。然后,使用KafkaProducer将这3000封邮件中的每封邮件发送到Kafka(2.x版)。

您将如何发送这3000条消息?

我既不能增加IBM MQ中的队列数(不受我的控制),也不能增加主题中的分区数(消息的顺序是必需的,并且编写自定义分区程序将影响该主题的太多使用者)

生产者设置当前为:

  • acks = 1
  • linger.ms = 0
  • batch.size = 65536

但是优化它们可能只是一个问题,而不是我当前问题的一部分。

当前,我只是在做

import org.apache.kafka.clients.producer.{KafkaProducer, ProducerRecord}

private lazy val kafkaProducer: KafkaProducer[String, String] = new KafkaProducer[String, String](someProperties)
val messages: Seq[String] = Seq(String1, …, String3000)
for (msg <- messages) {
    val future = kafkaProducer.send(new ProducerRecord[String, String](someTopic, someKey, msg))
    val recordMetadata = future.get()
}

在我看来,这似乎不是最优雅,最有效的方法。有没有一种编程方式来增加吞吐量,而无需更改任何配置/切换到Spark Streaming等,而只是通过编写更好的Scala代码?也许线程会有所帮助吗?

我是Scala的新手,因此对性能优化和并行性还不是很熟悉。


在@radai回答后编辑

感谢给出正确答案的答案,我仔细研究了不同的Producer方法。 《卡夫卡-权威指南》(O'Reilly)一书列出了以下方法:

  

一劳永逸   我们会向服务器发送一条消息,并不关心消息是否成功到达。大多数时候,它会成功到达,因为Kafka的可用性很高,并且生产者将重试自动发送消息。但是,使用此方法会丢失一些消息。

     

同步发送   我们发送一条消息,send()方法返回一个Future对象,然后使用get()   等待将来,看看send()是否成功。

     

异步发送   我们使用回调函数调用send()方法,该函数会在其回调时触发   收到Kafka经纪人的回复

现在我的代码看起来像这样(省去了错误处理和Callback类的简单定义):

  val asyncProducer = new KafkaProducer[String, String](someProperties)

  for (msg <- messages) {
    val record = new ProducerRecord[String, String](someTopic, someKey, msg)
    asyncProducer.send(record, new compareProducerCallback)
  }
  asyncProducer.flush()

我比较了10000条非常小的消息的所有方法。这是我的测量结果:

  1. 一劳永逸:173683464ns

  2. 同步发送:29195039875ns

  3. 异步发送:44153826ns

说实话,通过选择正确的属性(batch.size,linger.ms等),可能有更多的潜力来优化所有这些属性。但是,我想这已经反映出了潜力。 谢谢@radai的帮助!

1 个答案:

答案 0 :(得分:0)

我能看到您的代码运行缓慢的最大原因是,您在等待每个发送将来。

kafka旨在发送批次。通过一次发送一条记录,您将为每条记录等待往返时间,并且您不会从压缩中受益。

要做的“惯用”操作是发送所有内容,然后在第二个循环中阻止所有生成的期货。

此外,如果您打算执行此操作,则我将继续备份(否则,您的第一条记录将导致一批大小为1的文件,从而使您的整体速度变慢。请参见https://en.wikipedia.org/wiki/Nagle%27s_algorithm)并致电{{3}发送循环完成后,在生产者上进行}。