简体   繁体   English

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

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

I'd like to set up 3 retries.我想设置 3 次重试。 Here's what I'm visualizing, if the producer is done retrying 3 times and still hasn't sent the message, it should go to a local topic (dlt).这是我正在想象的,如果生产者完成了 3 次重试并且仍然没有发送消息,它应该 go 到本地主题(dlt)。

Here's what I'm working with right now.这就是我现在正在使用的东西。 This is the configuration这是配置

@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;
    }

This is the main application这是主要应用程序

@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);
        }

    }

This is the listener这是听众

@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();
            }

If you just want to retry 3 times and don't want too many components to be redundant, you can choose to use try catch to cooperate with the local Queue implementation.如果只想重试 3 次,又不想太多组件冗余,可以选择使用 try catch 配合本地 Queue 实现。

The simplest is to try again immediately after an error occurs .最简单的方法是在发生错误后立即重试 Of course, many times you will want to retry again every few minutes .当然,很多时候你会想每隔几分钟重试一次 At this time, you only need to put the error message into a queue in the catch, and then take out the queue data from another method and send it again .这时候只需要将错误信息放入catch中的一个队列中,然后再从另一个方法中取出队列数据再发送即可。 But maybe kafka has solved this problem for you, some exceptions can be retried automatically , I suggest you to understand: https://kafka.apache.org/21/documentation.html#producerconfigs不过也许kafka已经为你解决了这个问题,有些异常可以自动重试,建议你理解: https://kafka.apache.org/21/documentation.html#producerconfigs

The following is the simplest implementation:下面是最简单的实现:

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 directly supports this configuration in its producers as mentioned here .如此处所述,Kafka 直接在其生产者中支持配置。

The best way to do so though is using a combination of delivery.timeout.ms , request.timeout.ms and retry.backoff.ms properties to control how many retries will happen within a given period of time, as explained in the docs.但是,最好的方法是使用delivery.timeout.msrequest.timeout.msretry.backoff.ms属性的组合来控制在给定时间段内发生的重试次数,如文档中所述。

If you are using Spring Boot, you can configure a bean as follows:如果你使用的是 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