【问题标题】:how to get KafkaListener Consumer如何获取 KafkaListener 消费者
【发布时间】:2019-10-28 06:26:36
【问题描述】:

我将 spring-kafka 用于 springboot 2.0.4.RELEASE。

并使用 KafkaListener 获取消息

现在我想为我的组重置偏移量

但我不知道如何为该组获取消费者

    @KafkaListener(id="test",topics={"test"},groupId="group",containerFactory="batchContainerFactory")
    public String listenTopic33(List<ConsumerRecord<Integer, String>> record, Acknowledgment ack){
// do something

    }


    @Autowired
    KafkaListenerEndpointRegistry kafkaListenerEndpointRegistry;

    public void test() {

        MessageListenerContainer test3 = kafkaListenerEndpointRegistry.getListenerContainer("test3");
}

【问题讨论】:

  • @Gary Russell 可以帮我吗?
  • 您想什么时候进行重置?在听众本身,还是来自其他地方?
  • 我想从某个地方打电话。并得到消费者。使用 Map offsetsForTimes = consumer.offsetsForTimes(endTimestampsToSearch);获取每个 TopicPartition OffsetAndTimestamp。谢谢。

标签: spring spring-kafka


【解决方案1】:

如果你想在监听器本身中寻找消费者,只需在监听器方法中添加一个Consumer&lt;?, ?&gt; consumer参数即可。

请记住,容器可能已获取更多消息,因此您将在搜索生效之前获取它们。你可以设置max.poll.records=1 来避免这种情况。

你也可以在容器中添加自定义RemainingRecordsErrorHandler,在监听器中抛出异常,错误处理程序会获取剩余的记录而不是监听器。

另见Seeking to a Specific Offset

为了寻找,你的监听器必须实现 ConsumerSeekAware,它有以下方法:

void registerSeekCallback(ConsumerSeekCallback callback);

void onPartitionsAssigned(Map<TopicPartition, Long> assignments, ConsumerSeekCallback callback);

void onIdleContainer(Map<TopicPartition, Long> assignments, ConsumerSeekCallback callback);

第一个方法在容器启动时被调用。在初始化后的任意时间进行搜索时,您应该使用此回调。您应该保存对回调的引用。如果您在多个容器(或 ConcurrentMessageListenerContainer)中使用相同的侦听器,则应将回调存储在 ThreadLocal 或其他由侦听器 Thread 键入的结构中。

当使用组管理时,当分配改变时调用第二种方法。您可以使用此方法,例如,通过调用回调设置分区的初始偏移量。您必须使用回调参数,而不是传递给 registerSeekCallback 的参数。如果您自己显式分配分区,则永远不会调用此方法。在这种情况下使用 TopicPartitionInitialOffset。

回调有以下方法:

void seek(String topic, int partition, long offset);

void seekToBeginning(String topic, int partition);

void seekToEnd(String topic, int partition);

当检测到空闲容器时,您还可以从 onIdleContainer() 执行查找操作。有关如何启用空闲容器检测的信息,请参阅检测空闲和非响应消费者。

要在运行时任意搜索,请使用来自 registerSeekCallback 的回调引用以用于相应的线程。

这是一个例子;我们跟踪每个主题/分区的回调...

@SpringBootApplication
public class So56584233Application {

    public static void main(String[] args) {
        SpringApplication.run(So56584233Application.class, args);
    }

    @Bean
    public ApplicationRunner runner(Listener listener, KafkaTemplate<String, String> template) {
        return args -> {
            IntStream.range(0, 10).forEach(i -> template.send(new ProducerRecord<>("so56584233", i % 3, "foo", "bar")));
            while (true) {
                System.in.read();
                listener.seekToStart();
            }
        };
    }

    @Bean
    public NewTopic topic() {
        return new NewTopic("so56584233", 3, (short) 1);
    }

}

@Component
class Listener implements ConsumerSeekAware {


    private static final Logger logger = LoggerFactory.getLogger(Listener.class);


    private final Map<TopicPartition, ConsumerSeekCallback> callbacks = new ConcurrentHashMap<>();

    private static final ThreadLocal<ConsumerSeekCallback> callbackForThread = new ThreadLocal<>();

    @Override
    public void registerSeekCallback(ConsumerSeekCallback callback) {
        callbackForThread.set(callback);
    }

    @Override
    public void onPartitionsAssigned(Map<TopicPartition, Long> assignments, ConsumerSeekCallback callback) {
        assignments.keySet().forEach(tp -> this.callbacks.put(tp, callbackForThread.get()));
    }

    @Override
    public void onIdleContainer(Map<TopicPartition, Long> assignments, ConsumerSeekCallback callback) {
    }

    @KafkaListener(id = "so56584233", topics = "so56584233", concurrency = "3")
    public void listen(ConsumerRecord<String, String> in) {
        logger.info(in.toString());
    }

    public void seekToStart() {
        this.callbacks.forEach((tp, callback) -> callback.seekToBeginning(tp.topic(), tp.partition()));
    }

}

【讨论】:

  • 我添加了一个示例,说明如何在侦听器的上下文之外进行任意搜索。
  • 感谢您的帮助。但我需要按时间重置偏移量。例如昨天。所以我需要为 groupid 消费。使用代码 Map offsetsForTimes = consumer.offsetsForTimes(endTimestampsToSearch); .所以当我想重置时,我不知道如何获得消费者。你能帮我吗?@Gray Russell
  • this answer help you? ConsumerAwareRebalanceListener 在分配分区时被调用。你不能在任意线程上调用消费者,它不是线程安全的。如果稍后运行时需要更改偏移量,可以stop()容器并重新启动它;监听器将被再次调用。您需要更清楚地解释您的用例。
  • 谢谢。我已经使用 ConsumerAwareRebalanceListener 来解决它。
  • 嗨,Gary,在这个示例中,我们可以在 onPartitionsAssigned 方法中使用 callbackForThread.set(callback) 而不是 registerSeekCallback 吗?并在以后用它来寻找偏移量?
猜你喜欢
  • 1970-01-01
  • 2018-12-21
  • 2020-06-06
  • 1970-01-01
  • 2017-06-02
  • 1970-01-01
  • 2016-12-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多