我收到错误"偏移量从X变为0,某些数据可能已被遗漏"使用带有检查点的Spark Structured Streaming应用程序中的KafkaSource,但它似乎并没有造成任何问题。我试图找出错误实际意味着什么。
我的设置如下。
我在Docker容器中运行Kafka(0.10.1.0),并在/ tmp / kafka-logs上安装了命名卷,以便在重新启动之间保持日志。
我在另一个docker容器中有一个Spark Structured Streaming(2.1.1)应用程序。流消耗来自Kafka的数据。他们还在再次安装在命名卷中的位置使用检查点,以确保在重新启动之间保留元数据。
我使用了一个实现ForeachWriter接口的自定义接收器,这意味着我必须实现自己的已处理版本的日志,这样当所有内容重新启动时,我可以告诉Spark Streaming不要重新处理已经存在的内容已经处理完毕。
所有这些都运行良好,数据从Kafka正确消耗,我的自定义接收器正确处理它。
现在,如果我杀死Spark Streaming应用程序,让Kafka中的数据堆积起来,然后重新启动Spark Streaming,它将抛出以下错误,表明某些数据在Kafka中不再可用
ERROR StreamExecution: Query [id = cd2b69e1-2f24-439a-bebc-89e343df83a8, runId = d4b3ae65-8cfa-4713-912c-404623710048] terminated with error
Java.lang.IllegalStateException: Partition input.clientes-0's offset
was changed from 908 to 0, some data may have been missed.
Some data may have been lost because they are not available in Kafka
any more; either the data was aged out by Kafka or the topic may have
been deleted before all the data in the topic was processed. If you
don't want your streaming query to fail on such cases, set the source
option "failOnDataLoss" to "false".
at org.apache.spark.sql.kafka010.KafkaSource.org$apache$spark$sql$kafka010$KafkaSource$$reportDataLoss(KafkaSource.scala:329)
at org.apache.spark.sql.kafka010.KafkaSource$$anonfun$8.apply(KafkaSource.scala:283)
at org.apache.spark.sql.kafka010.KafkaSource$$anonfun$8.apply(KafkaSource.scala:281)
at scala.collection.TraversableLike$$anonfun$filterImpl$1.apply(TraversableLike.scala:248)
at scala.collection.mutable.ResizableArray$class.foreach(ResizableArray.scala:59)
at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:48)
at scala.collection.TraversableLike$class.filterImpl(TraversableLike.scala:247)
at scala.collection.TraversableLike$class.filter(TraversableLike.scala:259)
at scala.collection.AbstractTraversable.filter(Traversable.scala:104)
at org.apache.spark.sql.kafka010.KafkaSource.getBatch(KafkaSource.scala:281)
at org.apache.spark.sql.execution.streaming.StreamExecution$$anonfun$org$apache$spark$sql$execution$streaming$StreamExecution$$runBatch$2$$anonfun$apply$6.apply(StreamExecution.scala:452)
at org.apache.spark.sql.execution.streaming.StreamExecution$$anonfun$org$apache$spark$sql$execution$streaming$StreamExecution$$runBatch$2$$anonfun$apply$6.apply(StreamExecution.scala:448)
at scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:241)
at scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:241)
at scala.collection.Iterator$class.foreach(Iterator.scala:893)
at scala.collection.AbstractIterator.foreach(Iterator.scala:1336)
at scala.collection.IterableLike$class.foreach(IterableLike.scala:72)
at org.apache.spark.sql.execution.streaming.StreamProgress.foreach(StreamProgress.scala:25)
at scala.collection.TraversableLike$class.flatMap(TraversableLike.scala:241)
at org.apache.spark.sql.execution.streaming.StreamProgress.flatMap(StreamProgress.scala:25)
at org.apache.spark.sql.execution.streaming.StreamExecution$$anonfun$org$apache$spark$sql$execution$streaming$StreamExecution$$runBatch$2.apply(StreamExecution.scala:448)
at org.apache.spark.sql.execution.streaming.StreamExecution$$anonfun$org$apache$spark$sql$execution$streaming$StreamExecution$$runBatch$2.apply(StreamExecution.scala:448)
at org.apache.spark.sql.execution.streaming.ProgressReporter$class.reportTimeTaken(ProgressReporter.scala:262)
at org.apache.spark.sql.execution.streaming.StreamExecution.reportTimeTaken(StreamExecution.scala:46)
at org.apache.spark.sql.execution.streaming.StreamExecution.org$apache$spark$sql$execution$streaming$StreamExecution$$runBatch(StreamExecution.scala:447)
at org.apache.spark.sql.execution.streaming.StreamExecution$$anonfun$org$apache$spark$sql$execution$streaming$StreamExecution$$runBatches$1$$anonfun$1.apply$mcV$sp(StreamExecution.scala:255)
at org.apache.spark.sql.execution.streaming.StreamExecution$$anonfun$org$apache$spark$sql$execution$streaming$StreamExecution$$runBatches$1$$anonfun$1.apply(StreamExecution.scala:244)
at org.apache.spark.sql.execution.streaming.StreamExecution$$anonfun$org$apache$spark$sql$execution$streaming$StreamExecution$$runBatches$1$$anonfun$1.apply(StreamExecution.scala:244)
at org.apache.spark.sql.execution.streaming.ProgressReporter$class.reportTimeTaken(ProgressReporter.scala:262)
at org.apache.spark.sql.execution.streaming.StreamExecution.reportTimeTaken(StreamExecution.scala:46)
at org.apache.spark.sql.execution.streaming.StreamExecution$$anonfun$org$apache$spark$sql$execution$streaming$StreamExecution$$runBatches$1.apply$mcZ$sp(StreamExecution.scala:244)
at org.apache.spark.sql.execution.streaming.ProcessingTimeExecutor.execute(TriggerExecutor.scala:43)
at org.apache.spark.sql.execution.streaming.StreamExecution.org$apache$spark$sql$execution$streaming$StreamExecution$$runBatches(StreamExecution.scala:239)
at org.apache.spark.sql.execution.streaming.StreamExecution$$anon$1.run(StreamExecution.scala:177)
但是在错误被抛出之后,我看到我的流正常启动。 Spark Streaming正确地将已经堆积在Kafka中的数据推送到我的自定义接收器,具有预期版本。然后我的接收器继续并正确处理新数据。
因此错误表明某些数据在Kafka中不再可用,但它仍然设法被Spark Streaming正确使用。
如果我重新启动Spark Streaming应用程序,即使没有数据被推送到Kafka,我也会再次遇到相同的错误。如果我开始向Kafka推送新数据,它将继续由系统正确处理。
有人知道这里会发生什么吗?我是否错误地解释了错误?
答案 0 :(得分:1)
/tmp/kafka-logs
是Kafka的日志目录,其中存储了所有偏移量,主题信息。如果它已损坏或某些数据被删除,则需要在failOnDataLoss:false
的Kafka选项中设置选项SparkProcessContext
并重新启动Spark作业。
Option : failOnDataLoss
Value : true or false
Default : TRUE
含义:当数据可能丢失时是否使查询失败(例如,删除主题或偏移超出范围)。这可能是误报。如果它无法按预期工作,您可以将其禁用。
答案 1 :(得分:0)
这似乎是旧版 kafka-clients 库中的一个已知错误。
SPARK-26267 的描述说
<块引用>"由于KAFKA-7703- KafkaConsumer.position may return a wrong offset after "seekToEnd" is called,当Kafka源尝试获取最新的偏移量时,可能会得到最早的偏移量,然后在下一次得到正确的最新偏移量时重新处理已经处理过的消息批。”
总而言之,引用参与其中的开发人员的话:
<块引用>“这是Kafka中的一个已知问题,请参阅KAFKA-7703。这在SPARK-26267中的2.4.1和3.0.0中已修复。请将Spark升级到更高版本。另一种可能是将Kafka升级到2.3 .0,其中 Kafka 端是固定的。”
<块引用>“KAFKA-7703 仅存在于 Kafka 1.1.0 及更高版本中,因此可能的解决方法是使用没有此问题的旧版本。这不会影响 Spark 2.3.x 及更低版本,因为我们使用 Kafka 0.10默认为 .0.1。”
在我们的案例中,我们在 HDP 3.1 平台上遇到了同样的问题。我们有 Spark 2.3.2 和 spark-sql-kafka 库 (https://mvnrepository.com/artifact/org.apache.spark/spark-sql-kafka-0-10_2.11/2.3.2.3.1.0.0-78),但是,使用 kafka-clients 2.0.0。这意味着我们由于后续条件而面临此错误:
通过删除包含 0
偏移量的批次号的“偏移量”子文件夹中的检查点文件,我们能够“解决”这个问题。
删除此文件时,请确保删除后子文件夹“commits”和“offset”中检查点文件中的批号仍然匹配。
这远不是一个理想的解决方案,尤其是对于生产环境。但是,如果您无法轻松更新库,这可能会有所帮助。