在Spark Streaming中如何处理旧数据并删除已处理的数据

时间:2017-12-06 15:23:53

标签: apache-spark spark-streaming

我们正在运行一个Spark流式传输作业,它从目录中检索文件(使用textFileStream)。 我们遇到的一个问题是作业已关闭,但文件仍在添加到目录中。 一旦作业再次启动,那些文件就不会被拾取(因为它们不是新的或在作业运行时被更改)但我们希望它们被处理。

1)有解决方案吗?有没有办法跟踪哪些文件已被处理,我们可以强迫"强迫"要收拾旧文件?

2)有没有办法删除处理过的文件?

2 个答案:

答案 0 :(得分:1)

以下文章几乎涵盖了您的所有问题。

https://blog.yanchen.im/2016/06/28/fileinputdstream-in-spark-streaming/

1)有解决方案吗?有没有办法跟踪哪些文件已被处理,我们可以强迫"强迫"要拿起旧文件?

当启动作业/应用程序时,流阅读器使用系统时钟启动批处理窗口。显然,之前创建的所有文件都将被忽略。尝试启用点校验

2)有没有办法删除已处理的文件?

删除文件可能是不必要的。如果检查点有效,则Spark会识别未处理的文件。如果由于某种原因要删除文件,请实现自定义输入格式和阅读器(请参阅文章)以捕获文件名并根据需要使用此信息。但我不推荐这种方法。

答案 1 :(得分:0)

是否可以删除已处理的文件?

根据我的经验,我无法使用检查点功能,因此我不得不删除/移动进入每个批次的已处理文件。

获取这些文件的方法有些棘手,但是基本上可以说它们是当前RDD的祖先(依赖项)。然后,我使用的是一种递归方法,该方法会爬网该结构并恢复以RDD开头的hdfs的名称。

  /**
    * Recursive method to extract original metadata files involved in this batch.
    * @param rdd Each RDD created for each batch.
    * @return All HDFS files originally read.
    */
   def extractSourceHDFSFiles(rdd: RDD[_]): Set[String] = {

     def extractSourceHDFSFilesWithAcc(rdd: List[RDD[_]]) : Set[String] = {

      rdd match {
        case Nil => Set()
        case head :: tail => {
          val name = head.toString()
          if (name.startsWith("hdfs")){
            Set(name.split(" ")(0)) ++ extractSourceHDFSFilesWithAcc(head.dependencies.map(_.rdd).toList) ++ extractSourceHDFSFilesWithAcc(tail)
          }
          else {
            extractSourceHDFSFilesWithAcc(head.dependencies.map(_.rdd).toList) ++ extractSourceHDFSFilesWithAcc(tail)
          }
        }
      }
    }

    extractSourceHDFSFilesWithAcc(rdd.dependencies.map(_.rdd).toList)
  }

因此,在forEachRDD方法中,您可以轻松地调用它:

stream.forEachRDD(rdd -> {

     val filesInBatch = extractSourceHDFSFiles(rdd)
    logger.info("Files to be processed:")

    // Process them

    // Delete them when you are done
})