给出以下代码:
def createKafkaStream(ssc: StreamingContext,
kafkaTopics: String, brokers: String): DStream[(String, String)] = {
// some configs here
KafkaUtils.createDirectStream[String, String, StringDecoder,
StringDecoder](ssc, props, topicsSet)
}
def consumerHandler(): StreamingContext = {
val ssc = new StreamingContext(sc, Seconds(10))
createKafkaStream(ssc, "someTopic", "my-kafka-ip:9092").foreachRDD(rdd => {
rdd.foreach { msg =>
// Now do some DataFrame-intensive work.
// As I understand things, DataFrame ops must be run
// on Workers as well as streaming consumers.
}
})
ssc
}
StreamingContext.getActive.foreach {
_.stop(stopSparkContext = false)
}
val ssc = StreamingContext.getActiveOrCreate(consumerHandler)
ssc.start()
ssc.awaitTermination()
我的理解是Spark和Kafka将自动协同工作以确定要部署到可用工作节点的消费者线程数量,这可能导致并行处理Kafka主题的消息。
但如果我不想要多个并行消费者呢?如果希望1和1的消费者从主题中读取下一条消息,完全处理它,然后重新开始并轮询下一条消息,那该怎么办呢?
另外,当我打电话时:
val ssc = new StreamingContext(sc, Seconds(10))
这是否意味着:
答案 0 :(得分:2)
但是,如果我不想要多个并行消费者呢?如果想要怎么办 1和1的消费者阅读主题中的下一条消息, 完全处理它,然后重新开始 轮询下一条消息。
如果这是你的用例,我会说为什么要使用Spark呢?它的全部优点是您可以并行读取。我能想到的唯一的hacky解决方法是使用单个分区创建一个Kafka主题,这会使Spark将整个偏移范围分配给单个工作者,但这很难看。
这是否意味着单个消费者线程将接收所有消息 在最近10秒内发布到该主题或单个 消费者线程将从主题接收下一条(单个)消息, 并且它将每10秒轮询下一条消息?
都不是。由于您使用直接(无接收器)流方法,这意味着每10秒,您的驱动程序将要求Kafka为他提供自上一批次以来已更改的偏移范围,对于所述主题的每个分区。然后,Spark将采用每个这样的偏移范围,并将其发送给其中一个工人直接从Kafka消费。这意味着使用直接流方法,Kafka分区与Spark分区之间存在1:1的对应关系。