结构化流传输如何确保文件接收器的一次写入语义正确?

时间:2019-08-29 06:57:17

标签: apache-spark spark-structured-streaming

我正在编写用于Spark结构化流的存储编写器,它将对给定的数据帧进行分区并写入另一个Blob存储帐户。 Spark文档说,它可以确保文件接收器的exactly once语义,但还说,只有在源可重播且接收器是幂等的情况下,才有可能只有一次语义。

  1. 如果以镶木地板格式编写,blob是否存储幂等接收器?

  2. 如果我做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()
      })

2 个答案:

答案 0 :(得分:3)

微批量流处理

我认为问题是关于微批流处理(不是连续流处理)的。

基于内部注册表的可用和已提交偏移量(对于当前流执行,也称为runId)以及常规检查点(在重新启动后保持处理状态),就可以保证语义一次。

  

只有在源可重播且接收器是幂等的情况下,语义才可能出现一次。

有可能重新处理已经处理但内部记录不正确的任何内容(见下文):

  • 这意味着流查询中的所有流源都应可重播,以允许轮询曾经请求过的数据。

  • 这也意味着接收器应该是幂等,因此可以成功添加已成功处理并添加到接收器中的数据,因为在结构化流设法记录之前就发生了故障成功处理的数据(偏移量)(在检查点)

内部人员

在处理任何流源或阅读器的可用数据(按偏移量)之前,MicroBatchExecution将偏移量提交给预写日志(WAL),并将以下INFO消息打印到日志中: / p>

  

批处理[currentBatchId]的承诺偏移量。元数据[offsetSeqMetadata]

仅当有新数据可用时(基于偏移量)或最后一次执行需要另一个微批进行状态管理时,才执行流查询(微批处理)。

addBatch 阶段,MicroBatchExecution请求一个SinkStreamWriteSupport来处理可用数据。

微批处理成功完成后,MicroBatchExecution会将可用的偏移量提交给提交检查点,并且该偏移量将被视为已处理。

MicroBatchExecution将以下调试消息打印到日志中:

  

已完成的批次[currentBatchId]

答案 1 :(得分:1)

当您使用foreachBatch时,请确保只保证foreachBatch仅调用一次。但是,如果您在执行foreachBatch的过程中遇到异常,spark将尝试为同一批次再次调用它。在这种情况下,如果我们存储到多个存储中并且在存储过程中发生异常,则可能会重复。 因此,您可以在存储过程中手动处理异常,以避免重复。

在我的实践中,如果需要存储到多个存储并使用支持提交的数据源api v2,则创建了自定义接收器。