我正在尝试在名为" test"的kafka主题上发送字数统计问题(在spark-scala中)的输出。见下面的代码:
val Dstream = KafkaUtils.createDirectStream[String, String, StringDecoder, StringDecoder](ssc, kafkaParams, topicsSet)
val lines = Dstream.map(f => f._2)
val words = lines.flatMap(_.split(" "))
val wordCounts = words.map(x => (x, 1)).reduceByKey(_ + _)
wordCounts.foreachRDD(
rdd => rdd.foreach(
f =>
{
val sendProps = new Properties()
sendProps.put("metadata.broker.list", brokers)
sendProps.put("serializer.class", "kafka.serializer.StringEncoder")
sendProps.put("producer.type", "async")
val config = new ProducerConfig(sendProps)
val producer = new Producer[String, String](config)
producer.send(new KeyedMessage[String, String]"test", f._1 + " " +f._2))
producer.close();
}))
问题是随机输出中缺少一些单词。我还注意到,如果我删除了声明
producer.close()
没有数据丢失。
这是否意味着 producer.close()在实际将数据放入缓冲区之前中断 producer.send(),因为该特定元组未被发送给消费者?如果是,我该如何关闭生产者而不会有数据丢失的风险?
以上是我最初的问题,并由Vale的答案解决。
现在,当我再次更改 producer.type 属性时 - 数据随机丢失。
sendProps.put("producer.type", "sync")
为了澄清 producer.send 正在运行我需要放在输出主题中的所有单词。但是,有些单词会丢失,并且不会显示在输出Kafka主题中。
答案 0 :(得分:1)
这很奇怪。 close()方法应该等待send完成,这就是引入close(time)方法的原因:as you can see here。
所以,我使用Java 7. rdd.foreach是否在每个分区内运行?或者它是否在每个元组上运行(我认为它在做什么)?
如果是后者,你能试试rdd.foreachPartition(refer to this)吗?因为你为每条线创建了一个生产者,我担心这可能会导致问题(虽然理论上它不应该)。