【问题标题】:How to consume from a different Kafka topic in each batch of a Spark Streaming job?如何在每批 Spark Streaming 作业中使用不同的 Kafka 主题?
【发布时间】:2018-10-10 19:16:04
【问题描述】:

我很确定没有简单的方法可以做到这一点,但这是我的用例:

我有一个 Spark Streaming 作业(版本 2.1.0),每个微批次的持续时间为 5 秒。

我的目标是在每个微批处理间隔使用 1 个不同主题的数据,总共 250 个 Kafka 主题。你可以把下面的代码作为一个简单的例子:

 val groupId:String = "first_group"
 val kafka_servers:String =  "datanode1:9092,datanode2:9092,datanode3:9092"

 val ss:SparkSession = SparkSession.builder().config("spark.streaming.unpersist","true").appName("ConsumerStream_test").getOrCreate()
 val ssc:StreamingContext= new StreamingContext(ss.sparkContext,Duration(5000))

val kafka_parameters:Map[String,Object]=Map(
"bootstrap.servers"       -> kafka_servers,
"key.deserializer"        -> classOf[StringDeserializer],
"value.deserializer"      -> classOf[ByteArrayDeserializer],
"heartbeat.interval.ms"   -> (1000:Integer),
"max.poll.interval.ms"    -> (100:Integer),
"enable.auto.commit"      -> (false: java.lang.Boolean),
"autoOffsetReset"         -> OffsetResetStrategy.EARLIEST,
//"connections.max.idle.ms" -> (5000:Integer),
"group.id"                -> groupId
)

val r = scala.util.Random
val kafka_list_one_topic=List("topic_"+ r.nextInt(250))

val consumer:DStream[ConsumerRecord[String,Array[Byte]]] = KafkaUtils.createDirectStream(ssc, LocationStrategies.PreferBrokers, ConsumerStrategies.
Subscribe[String, Array[Byte]](kafka_list_one_topic , kafka_parameters))

consumer.foreachRDD( eachRDD => {
     // DOING SOMETHING WITH THE DATA...
  })
ssc.start()
ssc.awaitTermination()

但是这种方法的问题是,Spark 只会运行一次初始代码(foreachRDD 命令之前的所有内容),以便创建 Kafka 消费者 DStream,但在接下来的微批处理中,它只运行“foreachRDD "声明。

例如,假设 r.nextInt(250) 返回 40。Spark Streaming 作业将连接到 topic_40 并处理其数据。但是在接下来的微批处理中,它仍然会连接到topic_40,并且忽略foreachRDD语句之前的所有命令。

我猜这是意料之中的,因为 foreachRDD 语句之前的代码只在 Spark 驱动程序上运行。

我的问题是,有没有一种方法可以做到这一点,而不必每 5 秒重新启动一次 Spark 应用程序?

谢谢。

【问题讨论】:

  • 你不能创建一个所有主题的列表并消费数据吗?
  • @ShankarKoirala ,如果我有 5 到 10 个主题可供消费,这种方法会很好。但是有 250 个,连接到 Kafka brokers 需要很长时间,主要是因为每个 topic 的连接不是并行的,而是顺序的(你可以在这里找到更多关于它的信息stackoverflow.com/a/34448362/4135691
  • @ShankarKoirala 每个主题都有一个分区并从不同的数据源接收数据。出于组织和可扩展性的目的,以这种方式分隔数据是一种常见的做法。
  • 我很想知道为什么你想这样做?您在这里尝试实现的设计模式是什么?
  • @RobinMoffatt,这里是用例:我有 250 个数据源,每个数据源通过 Kafka 生产者将数据发送到 kafka 主题。然后,Spark Streaming 作业每 5 秒从这些主题中消耗一次以处理该数据。但是,并非所有主题在给定的微批次中都有新数据。因此,根据主题偏移量,我确定应该在该微批次中连接哪些主题。我这样做是因为尝试同时连接到所有 250 个 kafka 主题需要的时间太长,而我需要达到的处理时间。

标签: scala apache-spark apache-kafka spark-streaming


【解决方案1】:

我的方法很简单,如果你希望它是真正随机的并且不关心任何其他后果,请将 kafka_list_one_topic 设为可变变量并在流代码中更改它。

val r = scala.util.Random
var kafka_list_one_topic=List("topic_"+ r.nextInt(250))

val consumer:DStream[ConsumerRecord[String,Array[Byte]]] = 
KafkaUtils.createDirectStream(ssc, LocationStrategies.PreferBrokers, 
ConsumerStrategies.
Subscribe[String, Array[Byte]](kafka_list_one_topic , kafka_parameters))

consumer.foreachRDD( eachRDD => {
 // DOING SOMETHING WITH THE DATA...
 kafka_list_one_topic=List("topic_"+ r.nextInt(250))
 })
ssc.start()
ssc.awaitTermination()

【讨论】:

  • 感谢您的回答。不幸的是,正如我上面所说,随机部分纯粹是一个示例,表明主题名称随每次迭代而变化。此外,消费者仍然只会连接到第一个值为 kafka_list_one 的主题,而永远不会连接到另一个主题,与 val 或 var 无关
猜你喜欢
  • 2018-07-15
  • 2018-10-26
  • 2016-10-27
  • 2020-04-01
  • 2019-07-12
  • 2019-11-23
  • 2017-09-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多