Spark Streaming异常:java.util.NoSuchElementException:None.get

时间:2018-06-22 11:35:42

标签: apache-spark hadoop apache-kafka apache-spark-sql spark-streaming

我正在通过将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中,我正在使用各自的依赖项:

  • spark-core_2.11
  • spark-sql_2.11
  • spark-streaming_2.11
  • spark-streaming-kafka-0-10_2.11

2 个答案:

答案 0 :(得分:2)

该错误是由于尝试同时运行多个spark上下文而引起的。将allowMultipleContexts设置为true通常用于测试目的,不建议使用。因此,解决您的问题的方法是确保在所有地方都使用相同的SparkContext。从代码中我们可以看到SparkContextsc)用于创建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)如此在实践中几乎没有用处,特别是在流式传输等数据属性可能随时间变化的情况下。