Spark SQL加载不到kafka数据

在Spark SQL中处理kafka流数据时,若删除checkpoint文件,会导致每次重启从批次0开始,且offset从earliest开始。由于FileSink会根据_spark_metadata目录检查已处理批次,因此在checkpoint丢失但输出文件存在的情况下,可能会出现长时间未处理数据的现象,直到找到新的未处理批次。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、问题背景

使用SparkSession加载kafka流数据,调试时加载kafka的offset都是设置为earliest,每次重启时删除checkpoint文件

Dataset<Row> dataset = this.sparkSession.readStream().format("kafka")
				.options(this.getSparkKafkaCommonOptions(sparkSession))
				.option("kafka.bootstrap.servers", ConfigConstMdt.MDT_STREAMING_KAFKA_SERVERS)
				.option("subscribe", ConfigConstMdt.MDT_STREAMING_KAFKA_TOPICS)
				.option("startingOffsets", ConfigConstMdt.MDT_STREAMING_KAFKA_OFFSETS)
				.load();

用以下方式写出处理结果到HDFS

StreamingQuery query = queryResult.writeStream().format("parquet")
		.option("path", outputPath)
		.option("checkpointLocation", ConfigConstMdt.MDT_STREAMING_PARSE_CHECKPOINT_DIR)
		.partitionBy("month", "day", "hour")
		.outputMode(OutputMode.Append())
		.trigger(Trigger.ProcessingTime(1, TimeUnit.MINUTES))
		.start();

二、问题现象

如下图,每个批次显示的读取kafka的偏移都在增加,但numInputRows为0,过很长时间numInputRows才开始不为0,也就是才开始处理数据。
在这里插入图片描述
三、问题原因

1、删除checkpoint之后,启动以后从currentBatchId=0开始处理

private def populateStartOffsets(sparkSessionToRunBatches: SparkSession): Unit = {
    offsetLog.getLatest() match {
      case Some((latestBatchId, nextOffsets)) =>
      ......
      // checkpoint文件被删除,会匹配到这里
      case None => // We are starting this stream for the first time.
        logInfo(s"Starting new streaming query.")
        currentBatchId = 0
        watermarkTracker = WatermarkTracker(sparkSessionToRunBatches.conf)
    }
  }

看看offsetLog,以下代码说明批次加载要先去访问checkpoint文件记录计算起始偏移

val offsetLog = new OffsetSeqLog(sparkSession, checkpointFile("offsets"))
val commitLog = new CommitLog(sparkSession, checkpointFile("commits"))

2、我们再看下FileSink写出时会怎么做

override def addBatch(batchId: Long, data: DataFrame): Unit = {
    // currentBatchId和获取到的已经处理过的最大批次ID进行比较,如果currentBatchId值比获取到的ID小,则跳过该批次ID的处
    // 理。
    if (batchId <= fileLog.getLatest().map(_._1).getOrElse(-1L)) {
      logInfo(s"Skipping already committed batch $batchId")
    } else {
     ......
      FileFormatWriter.write(
        sparkSession = sparkSession,
        plan = qe.executedPlan,
        fileFormat = fileFormat,
        committer = committer,
        outputSpec = FileFormatWriter.OutputSpec(path, Map.empty, qe.analyzed.output),
        hadoopConf = hadoopConf,
        partitionColumns = partitionColumns,
        bucketSpec = None,
        statsTrackers = Seq(basicWriteJobStatsTracker),
        options = options)
    }
  }

注意:这里的fileLog.getLatest()是读取_spark_metadata这个目录下的文件获取到的

四、结论

  在以MicroBatch的方式进行流式处理写出到hdfs时(也就是FileSink时),如果重启时checkpoint文件不存在,则从批次0开始处理,然后进行批次数据写出前,会先去输出路径下的_spark_metadata这个目录获取已经处理过的最大批次ID,以避免重复处理相同批次。所以在重启时,如果删除了checkpoint目录,而没有删除之前的输出,便会出现二中的加载不到kafka数据的现象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值