为什么Spark Streaming在访问偏移时使用重新分区的dstream与ClassCastException失败?

时间:2017-05-30 17:28:23

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

在我的Spark应用程序中,我通过以下方式从Kafka主题创建DStream:

 KafkaUtils
  .createDirectStream[String, Array[Byte], StringDecoder, DefaultDecoder, (String, Array[Byte])](
    streamingContext,
    kafkaParams,
    offset.get,
    { message: MessageAndMetadata[String, Array[Byte]] => (message.key(), message.message()) }
  )

以后,我使用 asInstanceOf 函数向Kafka主题提交偏移量:

directKafkaStream.foreachRDD { rdd => 
 val offsetRanges = rdd.asInstanceOf[HasOffsetRanges]
 // offsetRanges.length = # of Kafka partitions being consumed
 ... }

在这种情况下一切正常,但如果我重新分配dstream,当我尝试提交偏移时,我有以下异常:

  

java.lang.ClassCastException:org.apache.spark.rdd.MapPartitionsRDD无法强制转换为org.apache.spark.streaming.kafka.HasOffsetRanges重新分区

有人可以帮助我吗?

1 个答案:

答案 0 :(得分:2)

为什么你repartition根本_?!_我说它是不允许的,因为分区数(在KafkaRDD中)正好是所谓的offset ranges的数量(即您从中读取记录的主题分区)。然后你就会损害" Spark已经计算出最佳的并行性和分布性。

  override def getPartitions: Array[Partition] = {
    offsetRanges.zipWithIndex.map { case (o, i) =>
        new KafkaRDDPartition(i, o.topic, o.partition, o.fromOffset, o.untilOffset)
    }.toArray
  }

此外, KafkaRDDHasOffsetRanges

private[spark] class KafkaRDD[K, V](
  ...
  ) extends RDD[ConsumerRecord[K, V]](sc, Nil) with Logging with HasOffsetRanges

Obtaining Offsets中的官方文档是这样说的:

  

请注意,只有在createDirectStream结果调用的第一个方法中完成对HasOffsetRanges的类型转换才会成功,而不是在方法链的后面。请注意,在任何混洗或重新分区的方法之后,RDD分区和Kafka分区之间的一对一映射不会保留,例如: reduceByKey()或window()。

RDD.repartition you simply create一个CoalescedRDD(所谓的 RDD血统):

...
  new CoalescedRDD(
    new ShuffledRDD[Int, T, T](mapPartitionsWithIndex(distributePartition),
    new HashPartitioner(numPartitions)),
    numPartitions,
    partitionCoalescer).values
} else {
  new CoalescedRDD(this, numPartitions, partitionCoalescer)
}

由于RDD没有HasOffsetRanges混合,因此您获得了ClassCastException

如果你想增加并行性(并且在Spark KafkaRDD中有更多的偏移范围),增加主题中的分区数量,Spark Streaming将很好地为你处理。

引用Spark Streaming + Kafka Integration Guide (Kafka broker version 0.10.0 or higher)(突出我的):

  

Kafka 0.10的Spark Streaming集成在设计上与0.8 Direct Stream方法类似。它提供简单的并行性,Kafka分区和Spark分区之间的 1:1对应关系,以及对偏移和元数据的访问。