我想知道在给一个实例分配了多个分区的情况下,Spring Kafka如何处理重试。 Spring Kafka是否根据重试策略和退避策略继续重试同一条消息,还是重试?在重试之间,它是否从其他分区发送消息?
是这种行为吗?
A)重试消息->重试消息->重试消息
B)重试消息->其他消息->重试消息->重试消息
我看过其他的stackoverflow问题,这些问题似乎可以确认给定一个分区,Spring Kafka不会移动到另一个偏移量,但是如果有多个分区分配给实例,则没有有关行为的信息。我已经实现了具有重试模板和有状态重试的工厂。
@Bean
public KafkaListenerContainerFactory<ConcurrentMessageListenerContainer<Integer, String>>
kafkaListenerContainerFactory() {
ConcurrentKafkaListenerContainerFactory<Integer, String> factory =
new ConcurrentKafkaListenerContainerFactory<>();
ListenerExceptions listenerExceptions = new ListenerExceptions();
factory.setConsumerFactory(consumerFactory());
factory.setConcurrency(KafkaProperties.CONCURRENCY);
factory.getContainerProperties().setPollTimeout(KafkaProperties.POLL_TIMEOUT_VLAUE);
factory.setRetryTemplate(retryTemplate());
factory.setErrorHandler(new SeekToCurrentErrorHandler());
factory.setStatefulRetry(true);
factory.setRecoveryCallback((RetryContext context) -> listenerExceptions.recover(context));
return factory;
}
答案 0 :(得分:1)
上述工厂的重试配置被委托到RetryingMessageListenerAdapter
中,其逻辑如下:
public void onMessage(final ConsumerRecord<K, V> record, final Acknowledgment acknowledgment,
final Consumer<?, ?> consumer) {
RetryState retryState = null;
if (this.stateful) {
retryState = new DefaultRetryState(record.topic() + "-" + record.partition() + "-" + record.offset());
}
getRetryTemplate().execute(context -> {
context.setAttribute(CONTEXT_RECORD, record);
switch (RetryingMessageListenerAdapter.this.delegateType) {
case ACKNOWLEDGING_CONSUMER_AWARE:
context.setAttribute(CONTEXT_ACKNOWLEDGMENT, acknowledgment);
context.setAttribute(CONTEXT_CONSUMER, consumer);
RetryingMessageListenerAdapter.this.delegate.onMessage(record, acknowledgment, consumer);
break;
case ACKNOWLEDGING:
context.setAttribute(CONTEXT_ACKNOWLEDGMENT, acknowledgment);
RetryingMessageListenerAdapter.this.delegate.onMessage(record, acknowledgment);
break;
case CONSUMER_AWARE:
context.setAttribute(CONTEXT_CONSUMER, consumer);
RetryingMessageListenerAdapter.this.delegate.onMessage(record, consumer);
break;
case SIMPLE:
RetryingMessageListenerAdapter.this.delegate.onMessage(record);
}
return null;
},
getRecoveryCallback(), retryState);
}
因此,我们会根据邮件重试。根据Apache Kafka的建议,我们在一个线程中处理一个分区,因此在重试用完或调用成功之前,将不会处理该分区中的下一个记录。
根据您的多个分区条件和factory.setConcurrency(KafkaProperties.CONCURRENCY);
配置,可能是在不同线程中处理了不同分区的事实。因此,可能存在同时重试来自不同分区的不同记录的情况。仅仅是因为重试与线程和调用堆栈相关。