执行程序失败后,Spark无法在HDFS中找到检查点数据

时间:2018-08-28 13:43:04

标签: apache-spark spark-streaming spark-checkpoint

我正在从卡夫卡获取数据,如下所示:

final JavaPairDStream<String, Row> transformedMessages = 


    rtStream
                    .mapToPair(record -> new Tuple2<String, GenericDataModel>(record.key(), record.value()))                
                    .mapWithState(StateSpec.function(updateDataFunc).numPartitions(32)).stateSnapshots()                        
                    .foreachRDD(rdd -> {
                    --logic goes here
                    }); 

我有四个工作线程,并且为此应用程序有多个执行程序,并且我正在尝试检查Spark的容错性。

由于我们正在使用mapWithState,所以spark将数据指向HDFS的检查点,因此,如果有任何执行者/工作人员崩溃,我们应该能够恢复丢失的数据(在失效执行者中丢失的数据),并继续处理剩余的执行者/工作人员

因此,我杀死了一个工作节点,以查看应用程序是否仍能平稳运行,但是我却得到了HDFS中FileNotFound的异常,如下所示:

这有点奇怪,因为有时HDFS中的Spark检查点数据为何无法找到它。显然,HDFS不会删除任何数据,所以为什么会出现此异常。

还是我在这里想念东西?

[ERROR] 2018-08-21 13:07:24,067 org.apache.spark.streaming.scheduler.JobScheduler logError - Error running job streaming job 1534871220000 ms.2
                org.apache.spark.SparkException: Job aborted due to stage failure: Task creation failed: java.io.FileNotFoundException: File does not exist: hdfs://mycluster/user/user1/sparkCheckpointData/2db59817-d954-41a7-9b9d-4ec874bc86de/rdd-1005/part-00000
                java.io.FileNotFoundException: File does not exist: hdfs://mycluster/user/user1/sparkCheckpointData/2db59817-d954-41a7-9b9d-4ec874bc86de/rdd-1005/part-00000
                        at org.apache.hadoop.hdfs.DistributedFileSystem$18.doCall(DistributedFileSystem.java:1122)
                at org.apache.hadoop.hdfs.DistributedFileSystem$18.doCall(DistributedFileSystem.java:1114)
                at org.apache.hadoop.fs.FileSystemLinkResolver.resolve(FileSystemLinkResolver.java:81)
                at org.apache.hadoop.hdfs.DistributedFileSystem.getFileStatus(DistributedFileSystem.java:1114)
                at org.apache.spark.rdd.ReliableCheckpointRDD.getPreferredLocations(ReliableCheckpointRDD.scala:89)
                at org.apache.spark.rdd.RDD$$anonfun$preferredLocations$1.apply(RDD.scala:273)
                at org.apache.spark.rdd.RDD$$anonfun$preferredLocations$1.apply(RDD.scala:273)
                at scala.Option.map(Option.scala:146)
                at org.apache.spark.rdd.RDD.preferredLocations(RDD.scala:273)
                at org.apache.spark.scheduler.DAGScheduler.org$apache$spark$scheduler$DAGScheduler$$getPreferredLocsInternal(DAGScheduler.scala:1615)
                at org.apache.spark.scheduler.DAGScheduler$$anonfun$org$apache$spark$scheduler$DAGScheduler$$getPreferredLocsInternal$2$$anonfun$apply$1.apply$mcVI$sp(DAGScheduler.scala:1626)
                at org.apache.spark.scheduler.DAGScheduler$$anonfun$org$apache$spark$scheduler$DAGScheduler$$getPreferredLocsInternal$2$$anonfun$apply$1.apply(DAGScheduler.scala:1625)
                at org.apache.spark.scheduler.DAGScheduler$$anonfun$org$apache$spark$scheduler$DAGScheduler$$getPreferredLocsInternal$2$$anonfun$apply$1.apply(DAGScheduler.scala:1625)
                at scala.collection.immutable.List.foreach(List.scala:381)
                at org.apache.spark.scheduler.DAGScheduler$$anonfun$org$apache$spark$scheduler$DAGScheduler$$getPreferredLocsInternal$2.apply(DAGScheduler.scala:1625)
                at org.apache.spark.scheduler.DAGScheduler$$anonfun$org$apache$spark$scheduler$DAGScheduler$$getPreferredLocsInternal$2.apply(DAGScheduler.scala:1623)

进一步更新: 我发现Spark试图在HDFS中找到的RDD已被“ ReliableRDDCheckpointData”过程删除,并且为检查点数据创建了新的RDD。 DAG以某种方式指向了这个旧的RDD。如果对此数据有任何引用,则不应删除该数据。

1 个答案:

答案 0 :(得分:0)

考虑在Spark流上进行以下转换:

rtStream
                    .mapToPair(record -> new Tuple2<String, GenericDataModel>(record.key(), record.value()))                
                    .mapWithState(StateSpec.function(updateDataFunc).numPartitions(32)).stateSnapshots()                        
                    .foreachRDD(rdd -> {
                      if(counter ==1){
                       --convert RDD to Dataset, and register it as a SQL table names "InitialDataTable"
                      } else
                       --convert RDD to Dataset, and register it as a SQL table names "ActualDataTable"


                    }); 

mapWithState与每批处理后的状态数据自动检查点相关联,因此上述“ forEachRdd”块中的每个“ rdd”都被检查点,并且在检查点时,它会覆盖先前的检查点(因为显然最新状态需要保留在其中)检查点)

但是可以说如果用户仍在使用rdd数字1,因为在我的情况下,我将第一个rdd注册为其他表,而将其他rdd注册为其他表,则不应将其覆盖。 (在Java中也是一样,如果某些对象引用了对象引用,则该对象将不符合垃圾回收的条件)

现在,当我尝试访问表“ InitialDataTable”时,显然用于创建该表的“ rdd”不再在内存中,因此它将进入HDFS从检查点恢复该表,并且找不到它在那里也存在,因为它被下一个rdd覆盖,并且spark应用程序停止引用原因。

“ org.apache.spark.SparkException:由于阶段失败而导致作业中止:任务创建失败:java.io.FileNotFoundException:文件不存在:hdfs:// mycluster / user / user1 / sparkCheckpointData / 2db59817-d954- 41a7-9b9d-4ec874bc86de / rdd-1005 / part-00000“

因此,要解决此问题,我必须明确检查第一个rdd。