ListenerContainerIdleEvent被触发的次数需要一些解释吗?

时间:2018-04-11 01:36:38

标签: spring-kafka

此问题与this相关联。

我有1个消费者从1个主题消耗3个分区。我已经设置了idleEventInterval = 30secs。每隔30秒,我会收到以下日志消息。

  

12:12:51.517 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO c.t.m.e.s.e.p.k.InboundMessageHandler - 没有收到30855毫秒的消息   12:12:51.517 [org.springframework.kafka.KafkaListenerEndpointContainer#1-0-C-1] INFO c.t.m.e.s.e.p.k.InboundMessageHandler - 没有收到30845毫秒的消息   12:12:51.517 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO c.t.m.e.s.e.p.k.InboundMessageHandler - partition:1 topic:test-topic   12:12:51.517 [org.springframework.kafka.KafkaListenerEndpointContainer#1-0-C-1] INFO c.t.m.e.s.e.p.k.InboundMessageHandler - partition:2 topic:test-topic   12:12:51.517 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO c.t.m.e.s.e.p.k.InboundMessageHandler - partition:0 topic:test-topic   12:12:51.517 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO c.t.m.e.s.e.p.k.InboundMessageHandler - 没有收到30855毫秒的消息   12:12:51.517 [org.springframework.kafka.KafkaListenerEndpointContainer#1-0-C-1] INFO c.t.m.e.s.e.p.k.InboundMessageHandler - 没有收到30845毫秒的消息   12:12:51.517 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO c.t.m.e.s.e.p.k.InboundMessageHandler - partition:1 topic:test-topic   12:12:51.517 [org.springframework.kafka.KafkaListenerEndpointContainer#1-0-C-1] INFO c.t.m.e.s.e.p.k.InboundMessageHandler - partition:2 topic:test-topic   12:12:51.517 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO c.t.m.e.s.e.p.k.InboundMessageHandler - partition:0 topic:test-topic

     

12:13:21.630 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO c.t.m.e.s.e.p.k.InboundMessageHandler - 没有收到60977毫秒的消息   12:13:21.630 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO c.t.m.e.s.e.p.k.InboundMessageHandler - partition:1 topic:test-topic   12:13:21.630 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO c.t.m.e.s.e.p.k.InboundMessageHandler - partition:0 topic:test-topic   12:13:21.630 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO c.t.m.e.s.e.p.k.InboundMessageHandler - 没有收到60977毫秒的消息   12:13:21.630 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO c.t.m.e.s.e.p.k.InboundMessageHandler - partition:1 topic:test-topic   12:13:21.630 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO c.t.m.e.s.e.p.k.InboundMessageHandler - partition:0 topic:test-topic   12:13:21.632 [org.springframework.kafka.KafkaListenerEndpointContainer#1-0-C-1] INFO c.t.m.e.s.e.p.k.InboundMessageHandler - 没有收到60975毫秒的消息   12:13:21.632 [org.springframework.kafka.KafkaListenerEndpointContainer#1-0-C-1] INFO c.t.m.e.s.e.p.k.InboundMessageHandler - partition:2 topic:test-topic   12:13:21.633 [org.springframework.kafka.KafkaListenerEndpointContainer#1-0-C-1] INFO c.t.m.e.s.e.p.k.InboundMessageHandler - 没有收到60975毫秒的消息   12:13:21.633 [org.springframework.kafka.KafkaListenerEndpointContainer#1-0-C-1] INFO c.t.m.e.s.e.p.k.InboundMessageHandler - partition:2 topic:test-topic

事件监听器代码是 -

  @EventListener
public void eventHandler(ListenerContainerIdleEvent event) {
    LOG.info("No messages received for " + event.getIdleTime() + " milliseconds");

Collection<org.apache.kafka.common.TopicPartition> partitions = event.getTopicPartitions();
partitions.forEach(p ->
    LOG.info("partition: " + p.partition() + " topic:" + p.topic()));

}

1)为什么这个事件每30秒被调用4次?

2)为什么每个消息集的分区信息不一致?有时没有分区信息,有时分区在同一组中重复,等等。

1 个答案:

答案 0 :(得分:1)

仔细阅读spring-kafka文档后会发现 - &#34;了解应用程序监听器将获取所有容器的事件非常重要#34;我能够选择正确的主题和分区空闲事件基于列表器的指定分区。下面的代码似乎运行良好。

在侦听器中实现ConsumerSeekAware接口...并通过覆盖onPartitionAssigned()方法保存分配给listen的分区 -

@Override
public void onPartitionsAssigned(Map<TopicPartition, Long> assignments, ConsumerSeekCallback callback) {
    assignedPartitions.clear();
    assignments.forEach((topicPartition, aLong) -> assignedPartitions.add(topicPartition.partition()));
}

然后在事件监听器中,仅在涉及相关主题和分区的情况下选择事件 -

 @EventListener
public void eventHandler(ListenerContainerIdleEvent event) {
    Collection<TopicPartition> topicPartitions = event.getTopicPartitions();
    topicPartitions.forEach(p -> {
        if (p.topic().equals(yourTopicName) && assignedPartitions.contains(p.partition()))
                        LOG.info("No messages on partition: " + p.partition() + " topic:" + p.topic());
         }
    );
}

我不确定为什么在上面我的情况下,监听器被调用了4次......我期待它被调用3次,每个分区一次。我没有在生产中观察到这种行为。