使用Kafka手册时,偶尔会收到“ Kafka Listner异常:提交无法完成”

时间:2019-10-24 07:07:14

标签: apache-kafka kafka-consumer-api spring-kafka

我们有带有手动确认功能的Kafka Consumer(并发数为5)。通过以下实施,有时会导致提交异常,因为该组已经重新平衡...

在“异常”情况下,该消息未被确认,并且再次被使用。

  

关于配置的任何建议都不会影响多大   消费者的表现?

消费工厂

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

消费者

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

2 个答案:

答案 0 :(得分:0)

您花费的时间太长,无法处理从上一个poll()收到的所有记录。

每次轮询中所有记录的处理必须在max.poll.interval.msConsumerConfig.MAX_POLL_INTERVAL_MS_CONFIG)内完成-默认5分钟。

弄清楚处理每条记录并增加max.poll.interval.ms或减少max.poll.records所花费的时间。

答案 1 :(得分:0)

您可以尝试在下面介绍的参数here

中进行尝试

session.timeout.ms (默认值:6秒)在每次轮询期间,消费者协调器将心跳发送给代理,以确保消费者的会话处于活动状态。如果直到session.timeout.ms经纪人之前经纪人都没有收到任何心跳信号,然后经纪人离开该消费者并进行重新平衡

注意:如果增加session.timeout.ms,请查看是否需要调整代理group.max.session.timeout.ms设置。

max.poll.interval.ms :(默认值:5分钟)使用使用者组管理时,两次poll()调用之间的最大延迟。这意味着使用者的最大时间将在获取更多记录之前处于空闲状态。如果在此超时到期之前未调用poll(),则该使用者被视为失败,并且该组将重新平衡

最大轮询记录数 :(默认值:500)单次调用poll()时返回的最大记录数。您可以尝试减少一次处理更少的记录

如果您仍然面临上述属性的问题,请在“订阅”旁边尝试在使用者中使用“分配”分区。

以下是设置值前的几点考虑:

  1. group.max.session.timeout.ms> session.timeout.ms> group.min.session.timeout.ms
  2. request.timeout.ms> session.timeout.ms
  3. heartbeat.interval.ms〜session.timeout.ms)/ 3(大约)