Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/apache-kafka/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Apache kafka 在卡夫卡中,如何根据制作时间获得精确的偏移量_Apache Kafka_Timestamp_Offset - Fatal编程技术网

Apache kafka 在卡夫卡中,如何根据制作时间获得精确的偏移量

Apache kafka 在卡夫卡中,如何根据制作时间获得精确的偏移量,apache-kafka,timestamp,offset,Apache Kafka,Timestamp,Offset,我需要在一天中一小时一小时地用卡夫卡传达信息。每一小时我将启动一个作业,以使用1小时前生成的消息。e、 例如,如果当前时间是20:12,我将在19:00:00和19:59:59之间使用消息。这意味着我需要在19:00:00之前获得开始偏移量,在19:59:59之前获得结束偏移量。我之前使用了SimpleConsumer.getOffsetsBefore,如“,”所示。问题是返回的偏移量与作为参数给定的时间戳不匹配。e、 g.当生成时间戳19:00:00时,我会得到在16:38:00时生成的消息。

我需要在一天中一小时一小时地用卡夫卡传达信息。每一小时我将启动一个作业,以使用1小时前生成的消息。e、 例如,如果当前时间是20:12,我将在19:00:00和19:59:59之间使用消息。这意味着我需要在19:00:00之前获得开始偏移量,在19:59:59之前获得结束偏移量。我之前使用了SimpleConsumer.getOffsetsBefore,如“,”所示。问题是返回的偏移量与作为参数给定的时间戳不匹配。e、 g.当生成时间戳19:00:00时,我会得到在16:38:00时生成的消息。

在卡夫卡中,目前无法获得对应于特定时间戳的偏移量-这是设计的。如图顶部所述,偏移量编号为日志提供了一种与挂钟时间解耦的时间戳。用偏移量作为时间的概念,你就可以知道任何两个系统是否处于一致的状态,只要知道它们读到什么偏移量就行了。对于不同服务器上的不同时钟时间、闰年、日光节约时间、时区等,从来没有任何混淆。这有点不错


现在。。。综上所述,如果您知道您的服务器在某个时间X发生故障,那么实际上,您很想知道相应的偏移量。你可以靠近。kafka机器上的日志文件是根据它们开始写入的时间命名的,并且存在一个kafka工具(我现在找不到),可以让您知道哪些偏移与这些文件关联。如果您想知道确切的时间戳,那么您必须在发送给卡夫卡的消息中对时间戳进行编码。

卡夫卡1.10确实支持时间戳,尽管使用它来做您想做的事情仍然是一个小挑战。但是,如果你知道你想从哪个时间戳开始阅读,直到你想阅读为止,那么你就可以在那之前轮询消息,并停止消费。

正如其他回复所指出的,卡夫卡的旧版本只有一种将时间映射到偏移量的近似方法。然而,自卡夫卡0.10.0(于2016年5月发布)以来,卡夫卡为每个主题保留了一个时间索引。这将允许您有效地从时间到精确偏移。您可以使用访问此信息


关于如何在页面上实现基于时间的索引,有更多详细信息。

如下kafka consumer api方法
getOffsetsByTimes()
可用于此,可从0.10.0或更高版本获得。看

/**
*按时间戳查找给定分区的偏移量。每个分区返回的偏移量是
*时间戳大于或等于相应分区中给定时间戳的最早偏移量。
*
*这是一个阻塞呼叫。不必为使用者分配分区。
*如果分区中的消息格式版本早于0.10.0,即消息没有时间戳,则为null
*将为该分区返回。
*
*请注意,如果分区不存在,此方法可能会无限期地阻塞。
*
*@param timestamp搜索从分区到时间戳的映射以查找。
*@返回从分区到时间戳的映射,以及时间戳大于的第一条消息的偏移量
*大于或等于目标时间戳。如果没有,则将为分区返回{@code null}
*这样的信息。
*如果目标时间戳为负,@将引发IllegalArgumentException。
*/
@凌驾
公共地图偏移时间(地图时间搜索){
for(Map.Entry:timestampsToSearch.entrySet()){
//我们在这里明确排除了最早和最晚的偏移量,因此返回
//偏移量和时间戳始终为正。
if(entry.getValue()<0)
抛出新的IllegalArgumentException(“分区”+entry.getKey()+“的目标时间为”+
entry.getValue()+”。目标时间不能为负。“);
}
返回fetcher.getOffsetsByTimes(timestampsToSearch、requestTimeoutMs);
}
显示代码:

public static Map<TopicPartition, OffsetAndTimestamp> getOffsetAndTimestampAtTime(String kafkaServer, String topic, long time) {
    Map<String, Object> kafkaParams = new HashMap<>();
    kafkaParams.put(BOOTSTRAP_SERVERS_CONFIG, kafkaServers);
    kafkaParams.put(GROUP_ID_CONFIG, "consumerGroupId");
    kafkaParams.put(KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
    kafkaParams.put(VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
    kafkaParams.put(AUTO_OFFSET_RESET_CONFIG, "latest");
    kafkaParams.put(ENABLE_AUTO_COMMIT_CONFIG, false);
    KafkaConsumer<String, String> consumer = new KafkaConsumer<>(kafkaParams);

    List<PartitionInfo> partitionInfos = consumer.partitionsFor(topic);

    List<TopicPartition> topicPartitions = partitionInfos
            .stream()
            .map(pi -> new TopicPartition(pi.topic(), pi.partition()))
            .collect(Collectors.toList());

    Map<TopicPartition, Long> topicPartitionToTimestampMap = topicPartitions.stream()
            .collect(Collectors.toMap(tp -> tp, tp -> time));

    Map<TopicPartition, OffsetAndTimestamp> result = consumer.offsetsForTimes(topicPartitionToTimestampMap);
    consumer.close();
    return result;
}
公共静态映射getOffsetAndTimeStattime(字符串kafkaServer,字符串主题,长时间){
Map kafkaParams=新HashMap();
kafkaParams.put(引导服务器配置,kafkaserver);
kafkaParams.put(GROUP_ID_CONFIG,“consumerGroupId”);
kafkaParams.put(键\反序列化器\类\配置,StringDeserializer.CLASS);
kafkaParams.put(值\反序列化器\类\配置,StringDeserializer.CLASS);
kafkaParams.put(自动偏移重置配置,“最新”);
kafkaParams.put(启用自动提交配置,false);
卡夫卡消费者=新卡夫卡消费者(卡夫卡消费者);
List PartitionInfo=消费者。用于(主题)的分区;
List topicPartitions=分区信息
.stream()
.map(pi->newtopicpartition(pi.topic(),pi.partition())
.collect(Collectors.toList());
映射topicPartitionToTimestampMap=topicPartitions.stream()
.collect(收集器.toMap(tp->tp,tp->time));
映射结果=消费者.offsetsForTimes(topicPartitionToTimestampMap);
consumer.close();
返回结果;
}

是的,我用“将你发送给卡夫卡的信息中的时间戳编码”解决了这个问题,现在已经运行了几个月。@PoZhou我也有一个问题,你能给我举个简单的例子吗。Thanx请注意,卡夫卡很快就会支持此功能:
public static Map<TopicPartition, OffsetAndTimestamp> getOffsetAndTimestampAtTime(String kafkaServer, String topic, long time) {
    Map<String, Object> kafkaParams = new HashMap<>();
    kafkaParams.put(BOOTSTRAP_SERVERS_CONFIG, kafkaServers);
    kafkaParams.put(GROUP_ID_CONFIG, "consumerGroupId");
    kafkaParams.put(KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
    kafkaParams.put(VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
    kafkaParams.put(AUTO_OFFSET_RESET_CONFIG, "latest");
    kafkaParams.put(ENABLE_AUTO_COMMIT_CONFIG, false);
    KafkaConsumer<String, String> consumer = new KafkaConsumer<>(kafkaParams);

    List<PartitionInfo> partitionInfos = consumer.partitionsFor(topic);

    List<TopicPartition> topicPartitions = partitionInfos
            .stream()
            .map(pi -> new TopicPartition(pi.topic(), pi.partition()))
            .collect(Collectors.toList());

    Map<TopicPartition, Long> topicPartitionToTimestampMap = topicPartitions.stream()
            .collect(Collectors.toMap(tp -> tp, tp -> time));

    Map<TopicPartition, OffsetAndTimestamp> result = consumer.offsetsForTimes(topicPartitionToTimestampMap);
    consumer.close();
    return result;
}