我正在尝试使用Alpakka Kafka connector (Akka Stream Kafka)创建一个简单的原型。
运行应用程序时出现以下错误:
com.typesafe.config.ConfigException$Missing: No configuration setting found for key 'kafka-clients'
我在./src/main/scala/App.scala
中有以下代码:
import akka.Done
import akka.actor.ActorSystem
import akka.kafka.ProducerSettings
import akka.kafka.scaladsl.Producer
import akka.stream.{ActorMaterializer, Materializer}
import akka.stream.scaladsl.Source
import com.typesafe.config.ConfigFactory
import org.apache.kafka.clients.producer.ProducerRecord
import org.apache.kafka.common.serialization.StringSerializer
import scala.concurrent.Future
object App {
def main(args: Array[String]): Unit = {
println("Hello from producer")
implicit val system = ActorSystem("fakeProducer")
implicit val materializer: Materializer = ActorMaterializer()
val config = system.settings.config // ConfigFactory.load()
val producerSettings =
ProducerSettings(config, new StringSerializer, new StringSerializer)
.withBootstrapServers("localhost:9092")
val done: Future[Done] =
Source(1 to 100)
.map(_.toString)
.map(value => new ProducerRecord[String, String]("test-basic-numbers", value))
.runWith(Producer.plainSink(producerSettings))
println("Done")
}
}
以下build.sbt
:
name := "test-akka-stream"
version := "0.1"
scalaVersion := "2.11.8"
libraryDependencies += "com.typesafe.akka" %% "akka-stream-kafka" % "0.21.1"
我使用sbt run
运行应用。我没有配置任何超级/装配罐。
我可能错过了一些显而易见的东西,但我看不到它......我怀疑akka依赖项存在一些问题。
正如@ terminally-chill调用ProducerSettings(system, new StringSerializer, new StringSerializer)
(传递ActorSystem
而不是配置)所建议的那样解决问题。我只是不明白这是设计还是错误。
我创建了一个已修复的github issue。现在,文档更准确,并解释了创建ProducerSettings
/ ConsumerSettings
的正确方法。
val config = system.settings.config.getConfig("akka.kafka.producer")
val producerSettings =
ProducerSettings(config, new StringSerializer, new StringSerializer)
.withBootstrapServers("localhost:9092")
或者您可以按照上面的说明传递ActorSystem
。
答案 0 :(得分:2)
感谢您在Alpakka Kafka连接器项目中注意到并提出问题。 该文档现已更新:https://doc.akka.io/docs/akka-stream-kafka/current/producer.html
答案 1 :(得分:1)
通常,我将所有配置保留在AkkaSystem实例中。我没有将Alpakka用于Kafka,但我的许多实现均基于源代码。
使用val config = ConfigFactory.load()
加载类型安全配置对象,然后将config
传递到val system = ActorSystem("fakeProducer", config)
。
最后,将system.settings.config
传递给ProducerSettings
。
您当前的代码未通过任何设置,因为尚未将配置加载到Akka系统中。您的val config = system.settings.config
引用的是一个空配置,其中没有kafka-clients部分(最好的猜测)。
答案 2 :(得分:1)
尽管我试图创建一个基本的“ hello world” Kafka消费者而不是生产者,但我认为我几乎遇到了与您相同的问题(几乎在同一时间)。我猜您只是在浏览Alpakka Kafka connector documentation中的文档,并遵循他们首次定义的示例
val config = system.settings.config
,然后将其传递到新的ConsumerSettings对象。我猜想在线文档存在缺陷,但是我对Akka Streams还是陌生的(这是我第一次通过示例学习的尝试),我没有资格弄清楚到底是对还是错。 / p>
我尝试创建和application.conf文件,然后执行ConfigFactory.load(),然后在创建时将其手动传递给ActorSystem,然后将该系统传递给ConsumerSettings构造函数,以及有关丢失的“ kafka客户端”消失了,但显然我什至不必这样做。如您所说,仅传递“ system”变量而不是“ config”变量即可达到目的。
希望这可以帮助在黑暗中同样摸索的人。我必须说,尽管Akka Streams周围有很多嗡嗡声,但似乎确实缺乏文档。一旦弄明白这些东西,我可能不得不写一篇博客文章!
答案 3 :(得分:1)
感谢@ terminally-chill和@ murray-todd-williams的回答。我进行了一些进一步的研究,并尝试在此处进行总结:
ConsumerSettings
和ProducerSettings
都具有apply
个函数,这些函数采用Config
(请参见here)或ActorSystem
(请参见{{3 }}。
问题在于,使用ActorSystem
时代码是:
val config = system.settings.config.getConfig("akka.kafka.consumer")
apply(config, keyDeserializer, valueDeserializer) // call the other overload
在使用Config
时,代码为:
val properties = ConfigSettings.parseKafkaClientsProperties(config.getConfig("kafka-clients"))
因此,当直接传递配置时,代码将搜索kafka-clients
属性,而不是传递ActorSystem
时,代码将检查akka.kafka.consumer/akka.kafka.producer
。
最后考虑一下,默认情况下,在创建ActorSystem
实例时,大多数设置都是从嵌入式reference.conf
文件加载的,并且与您的application.conf
文件合并(如果存在)。更多信息here。
因此,基本上唯一需要设置的属性通常是bootstrap.servers
。
因此,您现在可以理解为什么使用system.settings.config
时代码不起作用。此配置实例已加载reference.conf
(具有所有默认设置,请参见here)和自定义application.conf
。 kafka-clients
属性位于akka.kafka.consumer/akka.kafka.producer
内部,但是代码直接检查kafka-clients
。
一些可能的解决方案:
ActorSystem
system.settings.config.getConfig("akka.kafka.consumer")
Config
部分手动构建kafka-clients
实例对我来说,问题在于here提供的官方文档没有提及这些差异,并且提供的示例不完整和/或不精确。对于Akka专家来说,这可能很清楚,但是对于新开发人员而言,这可能会非常混乱。
我创建了一个更加“易于使用”的示例here,然后打开一个in this gist。