我正在编写用于Spark结构化流的存储编写器,它将对给定的数据帧进行分区并写入另一个Blob存储帐户。 Spark文档说,它可以确保文件接收器的exactly once
语义,但还说,只有在源可重播且接收器是幂等的情况下,才有可能只有一次语义。
如果以镶木地板格式编写,blob是否存储幂等接收器?
如果我做streamingDF.writestream.foreachbatch(...writing the DF here...).start()
,行为也会如何改变?仍然可以保证一次语义吗?
可能重复:How to get Kafka offsets for structured query for manual and reliable offset management?
Update#1:类似-
output
.writeStream
.foreachBatch((df: DataFrame, _: Long) => {
path = storagePaths(r.nextInt(3))
df.persist()
df.write.parquet(path)
df.unpersist()
})
答案 0 :(得分:3)
我认为问题是关于微批流处理(不是连续流处理)的。
基于内部注册表的可用和已提交偏移量(对于当前流执行,也称为runId
)以及常规检查点(在重新启动后保持处理状态),就可以保证语义一次。
只有在源可重播且接收器是幂等的情况下,语义才可能出现一次。
有可能重新处理已经处理但内部记录不正确的任何内容(见下文):
这意味着流查询中的所有流源都应可重播,以允许轮询曾经请求过的数据。
这也意味着接收器应该是幂等,因此可以成功添加已成功处理并添加到接收器中的数据,因为在结构化流设法记录之前就发生了故障成功处理的数据(偏移量)(在检查点)
在处理任何流源或阅读器的可用数据(按偏移量)之前,MicroBatchExecution
将偏移量提交给预写日志(WAL),并将以下INFO消息打印到日志中: / p>
批处理[currentBatchId]的承诺偏移量。元数据[offsetSeqMetadata]
仅当有新数据可用时(基于偏移量)或最后一次执行需要另一个微批进行状态管理时,才执行流查询(微批处理)。
在 addBatch 阶段,MicroBatchExecution
请求一个Sink
或StreamWriteSupport
来处理可用数据。
微批处理成功完成后,MicroBatchExecution
会将可用的偏移量提交给提交检查点,并且该偏移量将被视为已处理。
MicroBatchExecution
将以下调试消息打印到日志中:
已完成的批次[currentBatchId]
答案 1 :(得分:1)
当您使用foreachBatch时,请确保只保证foreachBatch仅调用一次。但是,如果您在执行foreachBatch的过程中遇到异常,spark将尝试为同一批次再次调用它。在这种情况下,如果我们存储到多个存储中并且在存储过程中发生异常,则可能会重复。 因此,您可以在存储过程中手动处理异常,以避免重复。
在我的实践中,如果需要存储到多个存储并使用支持提交的数据源api v2,则创建了自定义接收器。