在我的应用程序中,Web UI应用程序在完成文件上载过程后将文件路径发送到Kafka。
我有一个Spark Streaming应用程序,它使用JavaSparkContext
和JavaPairInputDStream
从Kafka中提取消息(因此它接收文件路径,但也可能有多个文件路径)。
我必须并行处理文件,并且需要将结果发送到另一个kafka流:
SparkConf conf = new SparkConf().setAppName("Task1").setMaster("local[*]");
sc = new JavaSparkContext(conf);
JavaStreamingContext ssc = new JavaStreamingContext(sc, new Duration(2000));
Map<String, String> kafkaParams = new HashMap<>();
kafkaParams.put("metadata.broker.list", "localhost:9092");
Set<String> topics = Collections.singleton("topic1");
JavaPairInputDStream<String, String> directKafkaStream = KafkaUtils.createDirectStream(ssc, String.class,
String.class, StringDecoder.class, StringDecoder.class, kafkaParams, topics);
directKafkaStream.foreachRDD(rdd -> {
rdd.collect().forEach((t) -> {
sendMessage(sc, t._2());
});
});
ssc.start();
ssc.awaitTermination();
sendMessage
会将数据发送到文件中。
在上面的实现中,我在foreachRDD方法中使用JavaSparkContext,这不是最佳实践。我想并行处理文件。
答案 0 :(得分:2)
我创建了一个函数sendMessage
,它将是一个纯粹的Kafka生成器(不依赖于Spark,尤其是JavaSparkContext
),它将向Kafka主题发送消息或者使用迭代器所有要发送的消息。
请参阅JMeter property。
使用纯粹的Kafka生成器作为sendMessage
我在Spark Streaming的转换中执行以下操作(内联注释应该给出一些关于每行发生的事情的提示):
def sendMessage(message: String) = {
println(s"Sending $message to Kafka")
}
dstream.map(_.value).foreachRDD { rdd =>
println(s"Received rdd: $rdd with ${rdd.count()} records")
// take paths from RDD that contains Kafka records with the file names
val files = rdd.collect()
files.foreach { f =>
// read a file `f` using Spark Core's RDD API
rdd.sparkContext.textFile(f).map { line =>
// do something with line
// this is the place for a pure Spark transformation
// it's as if you were outside Spark Streaming
println(line)
line
}.foreachPartition { linesAfterProcessingPerPartition =>
// send lines to Kafka
// they have been processed using Spark
linesAfterProcessingPerPartition.foreach { line =>
sendMessage(message = line)
}
}
}
}
我确信代码可以更清晰,但那就是Scala,你使用Java所以我会停在这里。
我强烈建议使用official documentation of Apache Kafka,因为很快就会取代Spark Streaming并成为Spark中的流媒体API。
答案 1 :(得分:1)
例如:
directKafkaStream.foreachRDD(new VoidFunction<JavaRDD<String>>() {
public void call(JavaRDD<String> stringJavaRDD) throws Exception {
stringJavaRDD.foreachPartition(new VoidFunction<Iterator<String>>() {
public void call(Iterator<String> stringIterator) throws Exception {
sendMessage(stringIterator);
}
});
}