在我的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重新分区
有人可以帮助我吗?
答案 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
}
此外,仅 KafkaRDD
为HasOffsetRanges:
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对应关系,以及对偏移和元数据的访问。