Apache kafka 《卡夫卡手册》中的“获得认可”;Kafka Listner异常:无法完成提交";偶尔地
我们有卡夫卡消费者(并发5)和手动确认。使用下面的实现,有时无法完成异常提交,因为组已重新平衡… 在异常场景中,消息未被确认,并且再次被使用 关于配置更改的任何建议都不会产生太大影响 关于消费者的表现 消费品工厂Apache kafka 《卡夫卡手册》中的“获得认可”;Kafka Listner异常:无法完成提交";偶尔地,apache-kafka,kafka-consumer-api,spring-kafka,Apache Kafka,Kafka Consumer Api,Spring Kafka,我们有卡夫卡消费者(并发5)和手动确认。使用下面的实现,有时无法完成异常提交,因为组已重新平衡… 在异常场景中,消息未被确认,并且再次被使用 关于配置更改的任何建议都不会产生太大影响 关于消费者的表现 消费品工厂 @EnableKafka @Configuration public class KafkaConsumerConfig { /* * Reading of the variables from yml file */ @Bean public ConsumerFact
@EnableKafka
@Configuration
public class KafkaConsumerConfig {
/*
* Reading of the variables from yml file
*/
@Bean
public ConsumerFactory<String, String> consumerFactory() {
Map<String, Object> props = new HashMap<>();
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaServers);
props.put(ConsumerConfig.GROUP_ID_CONFIG, kafkaGroupId);
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);
// SASL and JAAS properties
if(null!=kafkaTrustStoreFileLoc && !kafkaTrustStoreFileLoc.isEmpty() && isNotNullSslParams()) {
props.put(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, kafkaSecurityProtocol);
props.put(SaslConfigs.SASL_MECHANISM, kafkaSaslMechanism);
props.put(SslConfigs.SSL_TRUSTSTORE_LOCATION_CONFIG, kafkaTrustStoreFileLoc);
props.put(SslConfigs.SSL_ENDPOINT_IDENTIFICATION_ALGORITHM_CONFIG, kafkaSslIdentifyAlg);
String jaasTemplate = "org.apache.kafka.common.security.scram.ScramLoginModule required username=\"%s\" password=\"%s\";";
String jaasCfg = String.format(jaasTemplate, kafkaUsername, kafkaPassword);
props.put(SaslConfigs.SASL_JAAS_CONFIG, jaasCfg);
}
return new DefaultKafkaConsumerFactory<>(props);
}
protected boolean isNotNullSslParams() {
return null!=kafkaSecurityProtocol
&& null!= kafkaSaslMechanism
&& null!= kafkaSslIdentifyAlg
&& null!= kafkaUsername
&& null!= kafkaPassword;
}
@Bean
public ConcurrentKafkaListenerContainerFactory<String, String> kafkaListenerContainerFactory() {
ConcurrentKafkaListenerContainerFactory<String, String> factory = new ConcurrentKafkaListenerContainerFactory<>();
factory.setConsumerFactory(consumerFactory());
factory.getContainerProperties().setAckMode(AckMode.MANUAL_IMMEDIATE);
factory.setConcurrency(5);
return factory;
}
}
处理从上一次
poll()
收到的所有记录花费的时间太长
每次轮询的所有记录的处理必须在max.poll.interval.ms
(ConsumerConfig.max\u poll\u interval\u ms\u CONFIG
)默认5分钟内完成
计算处理每条记录所需的时间,增加
max.poll.interval.ms
或减少max.poll.records
您可以尝试以下参数
session.timeout.ms(默认值:6秒)在每次轮询期间,消费者协调员向代理发送心跳信号,以确保消费者的会话处于活动状态。若代理在session.timeout.ms broker之前并没有收到任何心跳信号,那个么代理将离开该消费者并进行重新平衡
注意:如果增加session.timeout.ms,请查看是否需要调整broker group.max.session.timeout.ms设置
max.poll.interval.ms:(默认值:5分钟)使用使用者组管理时调用poll()之间的最大延迟。这意味着在获取更多记录之前,使用者的最大时间将是空闲的。如果在此超时过期之前未调用poll(),则使用者将被视为失败,组将重新平衡
max.poll.records:(默认值:500)单个调用poll()返回的最大记录数。您可以尝试减少一次处理的记录数
若您仍然面临上述属性的问题,请在“订阅”旁边尝试在您的消费者中使用“分配”分区
以下是设定值前的几点注意事项:
@KafkaListener(topics = {"${kafka.topic}" }, containerFactory = "kafkaListenerContainerFactory")
public void listen(@Payload final String message,
@Header(KafkaHeaders.RECEIVED_TOPIC) final String topic, Acknowledgment ack) {
try {
log.debug("Received '{}'-message {} from Kafka", topic, message);
messageReceived(topic, message); //processing message
ack.acknowledge(); //ack the message
} catch (Exception e) {
log.error("Kafka Listener Exception : {} -> {}", e.getMessage(), e);
}
}