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条消息或达到起始偏移量。