Spark Kinesis流检查点恢复:RDD nullpointer异常

时间:2017-05-15 16:35:11

标签: apache-spark spark-streaming checkpointing

从检查点恢复失败的作业时,应用程序逻辑被正确调用并且RDD被重新实例化,但是对RDD.map的调用会导致NullPointerException。

lazy val ssc = StreamingContext.getOrCreate(checkpointDir, createStreamingContext _)

private def createStreamingContext: StreamingContext = {
  val ssc = new StreamingContext(spark.sparkContext, batchInterval)
  ssc.checkpoint(checkpointDir)
  consumeStreamingContext(ssc)
  ssc
}

def consumeStreamingContext(ssc: StreamingContext) = {
  //... create dstreams
  val dstream = KinesisUtil.createStream(....
  ...

  dstream.checkpoint(batchInterval)

  dstream
    .foreachRDD(process)
}

def process(events: RDD[Event]) = {
  if (!events.isEmpty()) {
    logger.info("Transforming events for processing")
    //rdd seems to support some operations? 
    logger.info(s"RDD LENGTH: ${events.count}")
    //nullpointer exception on call to .map
    val df = events.map(e => {
      ...
    }

  }
}

编辑:已更新,通知我已启用Kinesis和WAL。 S3上是否支持WAL检查点?我在其他地方读书并没有得到很好的支持。 https://issues.apache.org/jira/browse/SPARK-9215

编辑:我在使用HDFS时遇到了类似的结果。

2 个答案:

答案 0 :(得分:0)

解决方案是在foreach中的每次转换后调用rdd.checkpoint。必须对每个RDD转换进行检查点。

答案 1 :(得分:0)

我遇到了类似的问题 - 让我先解释一下我的问题,然后再解释一下。

问题陈述:使用火花流式消耗Kinesis数据。当火花流在kinesis之上工作时,我们仍然得到一个非结构化的流(DStream)而不是我们在听Kafka时得到的结构化流。

问题:将RDD转换为DF或DataSet时出现空指针异常。以下是有问题的代码:

def processData(spark: SparkSession, jobArgs: JobArgs, kinesisStream:ReceiverInputDStream[Array[Byte]]):Unit={
    val filenamesRDD = kinesisStream.map(decodeKinesisMessage)
    // Import spark implicits which add encoders for case classes.
    import spark.implicits._
    val events = filenamesRDD.flatMap(filenameToEvents(new AmazonS3Client))
    events.foreachRDD(rdd => {
      spark.createDataset(rdd)
        .write
        .partitionBy("date") // TODO add hour
        .mode(SaveMode.Append.name())
        .parquet(jobArgs.outputPath)
    })
}

问题是什么:当检查点目录不存在但检查点目录存在时出现Null Pointer Exception时,此代码有效。

为什么:我的理论是它试图通过反序列化来获取SQLContext和其他对象,但它们不可用。

我是如何解决的?:在将rdd转换为数据集之前再次构建SQLContext。请参阅以下代码:

def processData(spark: SparkSession, kinesisStream: ReceiverInputDStream[Array[Byte]]): Unit = {
    val filenamesRDD = kinesisStream.map(decodeKinesisMessage)
    // Import spark implicits which add encoders for case classes.
    import spark.implicits._
    val events = filenamesRDD.flatMap(filenameToEvents(new AmazonS3Client))

    events.foreachRDD(rdd => {
      val sqlContext = SparkSession.builder().getOrCreate().sqlContext
      import sqlContext.implicits._

      val outputPath: String = sqlContext.sparkSession.conf.get("output.path")
      sqlContext.createDataset(rdd)
        .write
        .partitionBy("date") // TODO add hour
        .mode(SaveMode.Append.name())
        .parquet(outputPath)
    })
}

如果有帮助,请告诉我。

谢谢, Hussain Bohra