繁体   English   中英

来自 Kafka 主题的 Spark Streaming 抛出超出范围的偏移量,无法重新启动流

[英]Spark Streaming from Kafka topic throws offset out of range with no option to restart the stream

我有一个在 Spark 2.1.1 上运行的流作业,轮询 Kafka 0.10。 我正在使用 Spark KafkaUtils类来创建 DStream,并且一切正常,直到我的数据由于保留策略而过期。 我的问题是当我停止工作以进行一些更改时,如果任何数据已超出主题范围,我会收到一条错误消息,指出我的偏移量超出范围。 我做了很多研究,包括查看 spark 源代码,我看到很多评论,比如这个问题中的评论: SPARK-19680 - 基本上是说数据不应该默默丢失 - 所以 auto.offset.reset 被忽略通过火花。 不过,我最大的问题是,我现在能做什么? 我的主题不会在 spark 中进行轮询 - 它在启动时因偏移异常而终止。 我不知道如何重置偏移量,所以我的工作将重新开始。 我没有启用检查点,因为我读到这些检查点对于这种用途是不可靠的。 我曾经有很多代码来管理偏移量,但是如果有任何提交,spark 似乎会忽略请求的偏移量,所以我目前正在管理这样的偏移量:

val stream = KafkaUtils.createDirectStream[String, T](
    ssc,
    PreferConsistent,
    Subscribe[String, T](topics, kafkaParams))

stream.foreachRDD { (rdd, batchTime) =>
    val offsets = rdd.asInstanceOf[HasOffsetRanges].offsetRanges
    Log.debug("processing new batch...")

    val values = rdd.map(x => x.value())
    val incomingFrame: Dataset[T] = SparkUtils.sparkSession.createDataset(values)(consumer.encoder()).persist

    consumer.processDataset(incomingFrame, batchTime)
    stream.asInstanceOf[CanCommitOffsets].commitAsync(offsets)
}
ssc.start()
ssc.awaitTermination()

作为一种解决方法,我一直在更改我的组 ID,但这真的很蹩脚。 我知道这是预期的行为,不应该发生,我只需要知道如何让流再次运行。 任何帮助,将不胜感激。

这是我编写的代码块,直到将真正的解决方案引入spark-streaming-kafka为止。 基本上,它会根据您设置的OffsetResetStrategy重置已过期的分区的偏移量。 只需给您提供给KafkaUtils的相同Map参数_params即可。 在从驱动程序调用KafkaUtils.create **** Stream()之前,请先调用此函数。

final OffsetResetStrategy offsetResetStrategy = OffsetResetStrategy.valueOf(_params.get(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG).toString().toUpperCase(Locale.ROOT));
if(OffsetResetStrategy.EARLIEST.equals(offsetResetStrategy) || OffsetResetStrategy.LATEST.equals(offsetResetStrategy)) {
    LOG.info("Going to reset consumer offsets");
    final KafkaConsumer<K,V> consumer = new KafkaConsumer<>(_params);

    LOG.debug("Fetching current state");
    final List<TopicPartition> parts = new LinkedList<>();
    final Map<TopicPartition, OffsetAndMetadata> currentCommited = new HashMap<>();
    for(String topic: this.topics()) {
        List<PartitionInfo> info = consumer.partitionsFor(topic);
        for(PartitionInfo i: info) {
            final TopicPartition p = new TopicPartition(topic, i.partition());
            final OffsetAndMetadata m = consumer.committed(p);
            parts.add(p);
            currentCommited.put(p, m);
        }
    }
    final Map<TopicPartition, Long> begining = consumer.beginningOffsets(parts);
    final Map<TopicPartition, Long> ending = consumer.endOffsets(parts);

    LOG.debug("Finding what offsets need to be adjusted");
    final Map<TopicPartition, OffsetAndMetadata> newCommit = new HashMap<>();
    for(TopicPartition part: parts) {
        final OffsetAndMetadata m = currentCommited.get(part);
        final Long begin = begining.get(part);
        final Long end = ending.get(part);

        if(m == null || m.offset() < begin) {
            LOG.info("Adjusting partition {}-{}; OffsetAndMeta={} Begining={} End={}", part.topic(), part.partition(), m, begin, end);

            final OffsetAndMetadata newMeta;
            if(OffsetResetStrategy.EARLIEST.equals(offsetResetStrategy)) {
                newMeta = new OffsetAndMetadata(begin);
            } else if(OffsetResetStrategy.LATEST.equals(offsetResetStrategy)) {
                newMeta = new OffsetAndMetadata(end);
            } else {
                newMeta = null;
            }

            LOG.info("New offset to be {}", newMeta);
            if(newMeta != null) {
                newCommit.put(part, newMeta);
            }
        }

    }
    consumer.commitSync(newCommit);
    consumer.close();
}

auto.offset.reset=latest/earliest将仅在使用者第一次启动时应用。

有Spark JIRA可以解决此问题,在此之前,我们需要现场解决。 https://issues.apache.org/jira/browse/SPARK-19680

尝试

auto.offset.reset=latest

要么

auto.offset.reset=earliest

最早:将偏移量自动重置为最早的偏移量

最新:自动将偏移量重置为最新偏移量

none:如果未找到消费者组的先前偏移量,则向消费者抛出异常

其他:向消费者抛出异常。

影响保留值与最小和最大配置相对应的另一件事是日志保留策略。 假设您有一个保留时间配置为1小时的主题。 您产生10条消息,然后一个小时后又发布10条消息。 最大偏移量将保持不变,但最小偏移量将不能为0,因为Kafka将已删除这些消息,因此最小可用偏移量将为10。

通过包含“failOnDataLoss”=“false”,在流结构化结构中解决了这个问题。 目前还不清楚为什么 spark DStream 框架中没有这样的选项。

这是 Spark 开发人员的一个大问题!

在我们的项目中,我们试图通过重置 ealiest + 5 分钟的偏移量来解决这个问题……这在大多数情况下都有帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM