繁体   English   中英

如何在 spring kafka 生产者上实现重试?

[英]How to implement retries on spring kafka producer?

我想设置 3 次重试。 这是我正在想象的,如果生产者完成了 3 次重试并且仍然没有发送消息,它应该 go 到本地主题(dlt)。

这就是我现在正在使用的东西。 这是配置

@Bean
    public ConcurrentKafkaListenerContainerFactory<?, ?> kafkaListenerContainerFactory(
            ConcurrentKafkaListenerContainerFactoryConfigurer configure,
            ConsumerFactory<Object, Object> kafkaConsumerFactory,
            KafkaTemplate<Object, Object> template) {
        ConcurrentKafkaListenerContainerFactory<Object, Object> factory = new ConcurrentKafkaListenerContainerFactory<>();
        configure.configure(factory, kafkaConsumerFactory);
        factory.setErrorHandler(new SeekToCurrentErrorHandler(new DeadLetterPublishingRecoverer(template), new FixedBackOff(0L, 2)));
        return factory;
    }

这是主要应用程序

@SpringBootApplication
@EnableKafka
@Retryable(value = Exception.class, maxAttemptsExpression = "3",
        backoff = @Backoff(delayExpression = "1000"))
public class KafkaApplication {

    public static void main(String[] args) throws Exception {
        ConfigurableApplicationContext context = SpringApplication.run(KafkaApplication.class, args);
        TestBean testBean = context.getBean(TestBean.class);
        while(true){
            for (int i = 0; i < 50; i++) {
                try{
                    Thread.sleep(5000);

                } catch (Exception e){
                    System.out.println("exception" + e.getMessage());
                }
                testBean.send("This is message " + i);
            }
            context.getBean(Consumer.Listener.class).latch.await(60, TimeUnit.SECONDS);
        }

    }

这是听众

@KafkaListener(topics = AppConfiguration.topic, groupId = AppConfiguration.groupid, containerFactory = "kafkaListenerContainerFactory")
        public void listen(@Payload String message, @Header(KafkaHeaders.RECEIVED_PARTITION_ID) int partition) {
            try{
                System.out.println("Successfully Received: " + message + " (partition: " + partition + ")");
                this.latch.countDown();
            } catch (Exception e){
                System.out.println("Error in sending record");
                System.out.println(e);
                e.printStackTrace();
            }

如果只想重试 3 次,又不想太多组件冗余,可以选择使用 try catch 配合本地 Queue 实现。

最简单的方法是在发生错误后立即重试 当然,很多时候你会想每隔几分钟重试一次 这时候只需要将错误信息放入catch中的一个队列中,然后再从另一个方法中取出队列数据再发送即可。 不过也许kafka已经为你解决了这个问题,有些异常可以自动重试,建议你理解: https://kafka.apache.org/21/documentation.html#producerconfigs

下面是最简单的实现:

public void sendToKafka(String topic, String key, String value, Integer retryTimes) {
        try {
            kafkaTemplate.send(topic, key, value);
        } catch (Exception e) {
            //if retryTimes
            if (retryTimes < 3) {
                sendToKafka(topic, key, value, ++retryTimes);
            }
        }
    }

如此处所述,Kafka 直接在其生产者中支持配置。

但是,最好的方法是使用delivery.timeout.msrequest.timeout.msretry.backoff.ms属性的组合来控制在给定时间段内发生的重试次数,如文档中所述。

如果你使用的是 Spring Boot,你可以配置一个 bean 如下:

  @Bean(name = "ProducerConfig")
  public Map<String, Object> producerConfig() {
    return Map.of(
        ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,
        bootstrapServers,
        // Enable safely ordered retries
        ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, "true",
        ProducerConfig.ACKS_CONFIG, "all",
        // Config number of retries
        ProducerConfig.DELIVERY_TIMEOUT_MS_CONFIG, 5000,
        ProducerConfig.REQUEST_TIMEOUT_MS_CONFIG, 200, 
        ProducerConfig.RETRY_BACKOFF_MS_CONFIG, 500
    );

  }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM