当并发级别小于分区数时,Spring Kafka SeekToCurrentErrorHandler maxFailures不起作用

时间:2019-09-11 12:40:06

标签: apache-kafka spring-kafka

我正在使用spring kafka 2.2.7,我的使用者配置代码如下:

@Slf4j
@Configuration
@EnableKafka
public class KafkaConfiguration {

  @Bean
  ConcurrentKafkaListenerContainerFactory<String, Customer> kafkaListenerContainerFactory() {
    ConcurrentKafkaListenerContainerFactory<String, Customer> factory = new ConcurrentKafkaListenerContainerFactory<>();
    factory.setConsumerFactory(consumerFactory());
    // less than number of partition, will do infinite retry
    factory.setConcurrency(1);
    SeekToCurrentErrorHandler errorHandler =
        new SeekToCurrentErrorHandler((record, exception) -> {
          LOGGER.info("***in error handler data, {}", record);
        }, 1);
    factory.setErrorHandler(errorHandler);
    return factory;
  }

  @Bean
  public ConsumerFactory<String, Customer> consumerFactory() {
    return new DefaultKafkaConsumerFactory<>(consumerConfigs());
  }

  @Bean
  public Map<String, Object> consumerConfigs() {
    Map<String, Object> props = new HashMap<>();
    props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
    props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
    props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, ErrorHandlingDeserializer2.class);
    props.put(ErrorHandlingDeserializer2.VALUE_DESERIALIZER_CLASS, KafkaAvroDeserializer.class);

    props.put("schema.registry.url", "http://127.0.0.1:8081");
    props.put("specific.avro.reader", "true");

    props.put(ConsumerConfig.GROUP_ID_CONFIG, groupId);
    props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
    props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "false");
    return props;
  }
}


@Component
@Slf4j
public class KafkaConsumerService {

  @KafkaListener(id = "demo-consumer-stream-group", topics = "kafka-demo-avro")
  public void process(ConsumerRecord<String, Customer> record) {
    LOGGER.info("Customer key: {} and value: {}", record.key(), record.value());
    LOGGER.info("topic: {}, partition: {}, offset: {}", record.topic(), record.partition(), record.offset());
    throw new RuntimeException("force to retry");
  }
}

因此,如果我的侦听器中发生异常,即使我在配置中配置的maxFailures小于我主题的分区计数,即使我在配置中配置了maxFailures,使用者也将永远重试失败的消息。

只有在我至少一秒一间隔地发送消息时,它才有效。如果我批量发送该消息,则该行为将不起作用。除非重新启动使用者,否则它将无法正常工作。

复制步骤: 1.创建一个具有多个分区的主题,例如3或6 2.在Spring Kafka配置中,将并发级别指定为1 3.对于SeekToCurrentErrorHandler,将maxFailure指定为正值,例如3 4.向主题发送数十条消息

您将看到每条失败的消息将进行无限次重试,而不是我指定的maxFailure。此外,我可以看到许多消息落后于消费者的滞后。

但是,如果停止侦听器并再次启动侦听器,它将正确跳过失败的消息。

2 个答案:

答案 0 :(得分:1)

这是Spring Kafka 2.2.7.RELEASE的错误,但已在2.2.8.RELEASE中修复。

答案 1 :(得分:0)

我使用的是2.2.8,我仍然可以重现该错误,但是配置更为复杂。我需要同时将SeekToCurrentEHretryTemplateExponentialRandomBackOffPolicy一起使用。因此,仍然有碰到它的风险。 已报告here