Java Spring Kafka-为任何主题的分区使用最后N条消息

Java Spring Kafka-为任何主题的分区使用最后N条消息,java,spring,apache-kafka,apache-kafka-streams,spring-kafka,Java,Spring,Apache Kafka,Apache Kafka Streams,Spring Kafka,我正试图阅读卡夫卡的信息。 对于非事务性消息,我们将在每个分区的当前偏移量小于结束偏移量的情况下,从endoffset-N为M个分区开始轮询并收集消息。对于幂等/事务性消息,我们必须考虑事务标记/重复消息,并且意义偏移量不会是连续的,在这种情况下,endoffset-N不会返回N条消息,我们需要返回并寻找更多消息,直到每个分区有N条消息,或者达到起始偏移量 由于有多个分区,我需要跟踪所有读取的偏移量,以便在完成所有操作后停止。有两个步骤,第一步计算开始偏移量(结束偏移量-请求的消息数)和结束偏移

我正试图阅读卡夫卡的信息。
对于非事务性消息,我们将在每个分区的当前偏移量小于结束偏移量的情况下,从endoffset-N为M个分区开始轮询并收集消息。对于幂等/事务性消息,我们必须考虑事务标记/重复消息,并且意义偏移量不会是连续的,在这种情况下,endoffset-N不会返回N条消息,我们需要返回并寻找更多消息,直到每个分区有N条消息,或者达到起始偏移量

由于有多个分区,我需要跟踪所有读取的偏移量,以便在完成所有操作后停止。有两个步骤,第一步计算开始偏移量(结束偏移量-请求的消息数)和结束偏移量。(偏移量不是连续的,因为存在间隙),我会从开始偏移量开始寻找分区。第二步是轮询消息并统计每个分区中的消息,如果我们不满足请求的消息数,则再次重复第一步和第二步,直到我们满足每个分区的消息数

条件

初始轮询可能不会返回任何记录,因此请继续轮询。 当到达每个分区的结束偏移量时停止轮询,或者轮询不返回任何结果。 检查每个分区中读取的消息是否与请求的消息相同。如果是,则标记为完成,如果否,则标记为继续并重复步骤。解释消息中的漏洞。 应适用于事务性和非事务性生产者

问题:

我该如何跟踪每个分区已读取的所有消息并中断循环?如果有帮助,每个分区中的消息将按顺序排列

SpringKafka支持这样的用例吗?更多细节可以找到


更新:我要求读取每个分区中的最后N条消息。分区和没有消息是用户输入。我想在内存中保留所有偏移量管理。本质上,我们试图按照后进先出的顺序阅读信息。卡夫卡允许你向前阅读而不是向后阅读,这使得阅读变得很棘手

为什么会有这样的需要,我不明白。当队列中没有任何内容时,卡夫卡自己进行管理。如果消息从一个状态跳到另一个状态,则可以有单独的队列/主题。然而,我们可以这样做

当我们使用类似于-

ConsumerIterator<byte[], byte[]> it = something; //initialize consumer
while (it.hasNext()) {
  MessageAndMetadata<byte[], byte[]> messageAndMetadata = it.next();
  String kafkaMessage = new String(messageAndMetadata.message());
  int partition = messageAndMetadata.partition();
  long offset = messageAndMetadata.offset();
  boolean processed = false;
  do{
    long maxOffset = something; //fetch from db
    //if offset<maxOffset, then process messages and manual commit
    //else busy wait or something more useful
  }while(processed);
}
ConsumerIterator it=something//初始化消费者
while(it.hasNext()){
MessageAndMetadata MessageAndMetadata=it.next();
String kafkaMessage=新字符串(messageAndMetadata.message());
int partition=messageAndMetadata.partition();
long offset=messageAndMetadata.offset();
布尔值=假;
做{
long maxOffset=something;//从数据库获取

//如果偏移量那么如果我理解正确,这应该可以通过标准卡夫卡
消费者
实现

Consumer<?, Message> consumer = ...

public Map<Integer, List<Message>> readLatestFromPartitions(String topic, Collection<Integer> partitions, int count) {

    // create the TopicPartitions we want to read
    List<TopicPartition> tps = partitions.stream().map(p -> new TopicPartition(topic, p)).collect(toList());
    consumer.assign(tps);

    // create and initialize the result map
    Map<Integer, List<Message>> result = new HashMap<>();
    for (Integer i : partitions) { result.add(new ArrayList<>()); }

    // read until the expected count has been read for all partitions
    while (result.valueSet().stream().findAny(l -> l.size() < count)) {
        // read until the end of the topic
        ConsumerRecords<?, Message> records = consumer.poll(Duration.ofSeconds(5));
        while (records.count() > 0) {
            Iterator<ConsumerRecord<?, Message>> recordIterator = records.iterator();
            while (recordIterator.hasNext()) {
                ConsumerRecord<?, Message> record = recordIterator.next();
                List<Message> addTo = result.get(record.partition);
                // only allow 10 entries per partition
                if (addTo.size() >= count) {
                    addTo.remove(0);
                }
                addTo.add(record.value);
            }
            records = consumer.poll(Duration.ofSeconds(5));
        }
        // now we have read the whole topic for the given partitions.
        // if all lists contain the expected count, the loop will finish;
        // otherwise it will wait for more data to arrive.
    }

    // the map now contains the messages in the order they were sent,
    // we want them reversed (LIFO)
    Map<Integer, List<Message>> returnValue = new HashMap<>();
    result.forEach((k, v) -> returnValue.put(k, Collections.reverse(v)));
    return returnValue;
}

Consumery您的要求并不明确。如果您在自己的组中创建一个消费者,分区不适用……或者它与您所查找的信息相关吗?否则,我只需轮询并填写一个列表,直到出现超时,列表包含所需的元素数。抱歉,添加了更新。如果您仍然有q,请告诉我问题。你只是在读未读的信息吗?你说的是“用户输入”所以这不涉及轮询?@kentor它不受开箱即用的支持。我最终创建了一个迭代器来包装轮询结果,跟踪偏移量/分区,聚合结果并查找下一个以前的消息,直到满足请求的计数。谢谢@daniu。我现在正在尝试阅读关于该主题的现有消息。我们的用例是用户请求X主题的M部分上的N条消息,然后我应该能够从M个主题分区的结束偏移量返回N条消息。对于非事务性消息,我们将从endoffset-N中查找M个分区,开始轮询并收集当前偏移量小于每个分区的结束偏移量的消息。对于idem有效/事务性消息我们必须考虑事务标记/重复消息,并且意味着偏移量不会连续,在这种情况下,endoffset-N不会返回N条消息,我们需要返回并寻找更多消息,直到每个分区有N条消息或达到起始偏移量。