我正在通过将SparkStreaming
数据转换为数据帧来将其写入HDFS:
代码
object KafkaSparkHdfs {
val sparkConf = new SparkConf().setMaster("local[*]").setAppName("SparkKafka")
sparkConf.set("spark.driver.allowMultipleContexts", "true");
val sc = new SparkContext(sparkConf)
def main(args: Array[String]): Unit = {
val sqlContext = new org.apache.spark.sql.SQLContext(sc)
import sqlContext.implicits._
val ssc = new StreamingContext(sparkConf, Seconds(20))
val kafkaParams = Map[String, Object](
"bootstrap.servers" -> "localhost:9092",
"key.deserializer" -> classOf[StringDeserializer],
"value.deserializer" -> classOf[StringDeserializer],
"group.id" -> "stream3",
"auto.offset.reset" -> "latest",
"enable.auto.commit" -> (false: java.lang.Boolean)
)
val topics = Array("fridaydata")
val stream = KafkaUtils.createDirectStream[String, String](
ssc, PreferConsistent, Subscribe[String, String](topics, kafkaParams)
)
val lines = stream.map(consumerRecord => consumerRecord.value)
val words = lines.flatMap(_.split(" "))
val wordMap = words.map(word => (word, 1))
val wordCount = wordMap.reduceByKey(_ + _)
wordCount.foreachRDD(rdd => {
val dataframe = rdd.toDF();
dataframe.write
.mode(SaveMode.Append)
.save("hdfs://localhost:9000/newfile24")
})
ssc.start()
ssc.awaitTermination()
}
}
已创建文件夹,但未写入文件。
程序因以下错误而终止:
18/06/22 16:14:41 ERROR Executor: Exception in task 0.0 in stage 0.0 (TID 0)
java.util.NoSuchElementException: None.get
at scala.None$.get(Option.scala:347)
at scala.None$.get(Option.scala:345)
at org.apache.spark.storage.BlockInfoManager.releaseAllLocksForTask(BlockInfoManager.scala:343)
at org.apache.spark.storage.BlockManager.releaseAllLocksForTask(BlockManager.scala:670)
at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:289)
at java.lang.Thread.run(Thread.java:748)
18/06/22 16:14:41 WARN TaskSetManager: Lost task 0.0 in stage 0.0 (TID 0, localhost, executor driver): java.util.NoSuchElementException: None.get
at scala.None$.get(Option.scala:347)
at scala.None$.get(Option.scala:345)
at org.apache.spark.storage.BlockInfoManager.releaseAllLocksForTask(BlockInfoManager.scala:343)
at org.apache.spark.storage.BlockManager.releaseAllLocksForTask(BlockManager.scala:670)
at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:289)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
在pom中,我正在使用各自的依赖项:
答案 0 :(得分:2)
该错误是由于尝试同时运行多个spark上下文而引起的。将allowMultipleContexts
设置为true通常用于测试目的,不建议使用。因此,解决您的问题的方法是确保在所有地方都使用相同的SparkContext
。从代码中我们可以看到SparkContext
(sc
)用于创建SQLContext
很好。但是,在创建StreamingContext
时不使用它,而使用SparkConf
。
通过查看documentation,我们看到:
通过提供新SparkContext所需的配置来创建StreamingContext
换句话说,通过使用SparkConf
作为参数,将创建一个新的SparkContext
。现在有两个单独的上下文。
这里最简单的解决方案是继续使用与以前相同的上下文。将创建StreamingContext
的行更改为:
val ssc = new StreamingContext(sc, Seconds(20))
注意::在较新版本的Spark(2.0+)中,请使用SparkSession
。然后可以使用StreamingContext(spark.sparkContext, ...)
创建新的流上下文。它可以如下所示:
val spark = SparkSession().builder
.setMaster("local[*]")
.setAppName("SparkKafka")
.getOrCreate()
import sqlContext.implicits._
val ssc = new StreamingContext(spark.sparkContext, Seconds(20))
答案 1 :(得分:0)
这里有一个明显的问题-coalesce(1)
。
dataframe.coalesce(1)
尽管在许多情况下减少文件数量可能很诱人,但只有当其数据量足够低以至于节点需要处理时(显然不在此处),才应该这样做。
此外,让我引用the documentation:
但是,如果您要进行剧烈的合并,例如到numPartitions = 1,这可能会导致您的计算在少于您希望的节点上进行(例如,在numPartitions = 1的情况下为一个节点)。为避免这种情况,您可以调用重新分区。这将增加一个随机播放步骤,但是意味着当前的上游分区将并行执行(无论当前分区是什么)。
结论是您应该根据预期的数据量和预期的并行度来调整参数。 coalesce(1)
如此在实践中几乎没有用处,特别是在流式传输等数据属性可能随时间变化的情况下。