应用程序重启时Kafka的最后偏移量增加

时间:2017-05-25 13:45:17

标签: java akka apache-kafka

我有一个从Kafka读取的Java Akka应用程序,处理消息并手动提交。

我使用的是0.10.1.1 API的高级消费者。

奇怪的是,当我关闭应用程序并再次启动它时,偏移量比上一次提交略大,我找不到原因。

我在代码中只有一个提交点。

else if(message.getClass() == ProcessedBatches.class) {
        try {
            Logger.getRootLogger().info("[" + this.name + "/Reader] Commiting ...");
            ProcessedBatches msg = (ProcessedBatches) message;
            consumer.commitSync(msg.getCommitInfo());
            lastCommitData = msg.getCommitInfo();
            lastCommit = System.currentTimeMillis();
        } catch (CommitFailedException e) {
            Logger.getRootLogger().info("[" + this.name + "/Reader] Failed to commit... Last commit: " + lastCommit + " | Last batch: " + lastBatch + ". Current uncommited messages: " + uncommitedMessages);
            self().tell(HarakiriMessage.getInstance(), self());
        }
    }

提交后,我将偏移HashMap保存在lastCommitData中以便进行调试。

然后我添加了一个关闭钩子来打印lastCommitData变量来检查为每个分区提交的最后一个偏移量。

  Runtime.getRuntime().addShutdownHook(new Thread(() -> {
        String output = 
                "############## SHUTTING DOWN CONSUMER ############### \n" + 
                lastCommitData+"\n";
        System.out.println(output);
    }));

此外,我还有一个消费者重新平衡监听器,用于在消费者启动时检查每个分区的起始位置。

new ConsumerRebalanceListener() {
        @Override
        public void onPartitionsRevoked(Collection<TopicPartition> collection) {}

        @Override
        public void onPartitionsAssigned(Collection<TopicPartition> collection) {
            for (TopicPartition p:collection
                 ) {
                System.out.println("Starting position "+p.toString()+":" + consumer.position(p));
            }
            coordinator.setRebalanceTimestamp(System.currentTimeMillis());
        }
    });

一个分区的示例:

关机前偏移:3107169023

分配分区时的偏移量:3107180350

正如您所看到的,每个消息之间几乎有10K消息。

消费者属性如下:

    Properties props = new Properties();
    props.put("bootstrap.servers", bootstrapServers);
    props.put("group.id", group_id);
    props.put("enable.auto.commit", "false");
    props.put("auto.commit.interval.ms", "100000000");
    props.put("session.timeout.ms", "10000");
    props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
    props.put("value.deserializer", "org.apache.kafka.common.serialization.ByteArrayDeserializer");
    props.put("max.poll.records", "40000");
    props.put("auto.offset.reset", "latest");

我不确定我做错了什么。

3 个答案:

答案 0 :(得分:1)

我认为你根据你的关机挂钩打印假设的“Offset off off:3107169023”是否正确?

如果是这样,我会看到2个潜在问题。

注册关闭钩子时,您将关闭lastCommitData字段。

由于您是从另一个线程访问它,因此关闭钩子线程是声明为volatile的字段吗?否则您可能正在打印陈旧的值。

此外,java.lang.Runtime.addShutdownHook说:

  

当虚拟机开始其关闭序列时,它将以某种未指定的顺序启动所有已注册的关闭挂钩并让它们同时运行

因此无法保证在关闭钩子已经打印lastCommitData值之后,您的使用者将无法进一步提交偏移量。

我建议您检查Kafka,检查应用关闭后确实提供的实际承诺偏移量。

答案 1 :(得分:0)

检查我们主题的保留政策  可能就是当你重新启动你的消费者时,最后一个提交的偏移量可能已从分区中清除,消费者将向前移动到该分区的最新偏移量。

答案 2 :(得分:-1)

使用Consumer API轮询Kafka时,它会从分区中最后消耗的偏移量中读取。系统中必须有其他消费者必须拥有之前已被您停止的实例消耗的分区 - 因此最新的偏移量将会发生变化。由于您在退出之前知道自己处于哪个偏移量,因此需要将其保存到某个持久存储区 - 请使用ConsumerRebalanceListener#onPartitionsRevoked。重新启动消费者流程并将消费者指向该消费者流程时,请阅读该偏移量 - 通过调用seek(partition, offset)

中的ConsumerRebalanceListener#onPartitionsAssigned来执行此操作