从检查点恢复失败的作业时,应用程序逻辑被正确调用并且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时遇到了类似的结果。
答案 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