我们有使用Spark结构化流实现的流应用程序。它将尝试从kafka主题中读取数据并将其写入HDFS位置。
有时应用程序无法给出错误消息:
_spark_metadata/0 doesn't exist while compacting batch 9
java.lang.IllegalStateException: history/1523305060336/_spark_metadata/9.compact doesn't exist when compacting batch 19 (compactInterval: 10)
无法解决此问题。
我发现只有一个解决方案,那就是删除检查点位置文件,如果再次运行该应用程序,它将从头开始读取主题/数据,这对于生产应用程序来说是不可行的解决方案。
任何人都可以找到解决此错误的解决方案,这样我就不必删除检查点,并且可以从上次运行失败的地方继续。
删除检查点位置,该位置将从头开始启动应用程序并读取所有先前的数据。
应用程序示例代码:
spark.
readStream.
format("kafka")
.option("kafka.bootstrap.servers", <server list>)
.option("subscribe", <topic>)
.load()
spark.
writeStream.
format("csv").
option("format", "append").
option("path",hdfsPath).
option("checkpointlocation","")
.outputmode(append).start
需要解决方案而不删除检查指示位置
答案 0 :(得分:1)
错误信息
_spark_metadata/n.compact doesn't exist when compacting batch n+10
可以在你出现时出现
由于您不想删除检查点文件,您可以简单地将丢失的 Spark 元数据文件从旧文件接收器输出路径复制到新输出路径。请参阅下文以了解什么是“丢失的 Spark 元数据文件”。
要了解为什么会抛出此 IllegalStateException
,我们需要了解在提供的文件输出路径中幕后发生了什么。让 outPathBefore
成为此路径的名称。当您的流作业正在运行并处理数据时,该作业会创建一个文件夹 outPathBefore/_spark_metadata
。在该文件夹中,您将找到一个以微批次标识符命名的文件,其中包含数据已写入的文件(分区文件)列表,例如:
/home/mike/outPathBefore/_spark_metadata$ ls
0 1 2 3 4 5 6 7
在这种情况下,我们有 8 个微批次的详细信息。其中一个文件的内容如下
/home/mike/outPathBefore/_spark_metadata$ cat 0
v1
{"path":"file:///tmp/file/before/part-00000-99bdc705-70a2-410f-92ff-7ca9c369c58b-c000.csv","size":2287,"isDir":false,"modificationTime":1616075186000,"blockReplication":1,"blockSize":33554432,"action":"add"}
默认情况下,在每个第十个微批处理中,这些文件都会被压缩,这意味着文件 0、1、2、...、9 的内容将存储在 压缩的文件名为9.compact
。
此过程在随后的十个批次中连续,即在微批次 19 中,作业聚合了最后 10 个文件,即 9.compact, 10, 11, 12, ..., 19。
现在,假设流作业一直运行到微批处理 15,这意味着作业已创建以下文件:
/home/mike/outPathBefore/_spark_metadata/0
/home/mike/outPathBefore/_spark_metadata/1
...
/home/mike/outPathBefore/_spark_metadata/8
/home/mike/outPathBefore/_spark_metadata/9.compact
/home/mike/outPathBefore/_spark_metadata/10
...
/home/mike/outPathBefore/_spark_metadata/15
在第 15 个微批处理之后,您停止了流式作业并将文件接收器的输出路径更改为 outPathAfter
。当您保持相同的 checkpointLocation 时,流作业将继续使用 micro-batch 16。但是,它现在在新的输出路径中创建元数据文件:
/home/mike/outPathAfter/_spark_metadata/16
/home/mike/outPathAfter/_spark_metadata/17
...
现在,这是抛出异常的地方: 当达到微批次 19 时,作业尝试压缩来自 spark 元数据文件夹的第十个最新文件。但是,它只能找到文件 16、17、18,而找不到 9.compact、10 等。因此错误消息说:
java.lang.IllegalStateException: history/1523305060336/_spark_metadata/9.compact doesn't exist when compacting batch 19 (compactInterval: 10)
结构化流编程指南在 Recovery Semantics after Changes in a Streaming Query 上进行了解释:
<块引用>“更改文件接收器的输出目录不允许:sdf.writeStream.format("parquet").option("path", "/somePath") 到 sdf.writeStream。 format("parquet").option("path", "/anotherPath")"
Databricks 在文章 Streaming with File Sink: Problems with recovery if you change checkpoint or output directories
中也写了一些细节答案 1 :(得分:0)
由checkpointLocation
引起的错误,因为checkpointLocation
存储了旧的或已删除的数据信息。您只需要删除包含checkpointLocation
的文件夹。
浏览更多:https://kb.databricks.com/streaming/file-sink-streaming.html
示例:
df.writeStream
.format("parquet")
.outputMode("append")
.option("checkpointLocation", "D:/path/dir/checkpointLocation")
.option("path", "D:/path/dir/output")
.trigger(Trigger.ProcessingTime("5 seconds"))
.start()
.awaitTermination()
您需要删除目录checkpointLocation
。