Kafka重复阅读

时间:2017-08-02 20:49:26

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

我正在为我的项目使用 Kafka版 0.10.2.1 Spring boot

我有一个主题的5个分区,可由多个消费者(具有相同的Group-Id )使用,这些分区在不同的计算机上运行。

我面临的问题是

我正在使用这些Kafka警告日志重复读取单个消息

Auto offset commit failed for group my-consumer-group: Commit cannot be completed since the group has already rebalanced and assigned the partitions to another member. This means that the time between subsequent calls to poll() was longer than the configured max.poll.interval.ms, which typically implies that the poll loop is spending too much time message processing. You can address this either by increasing the session timeout or by reducing the maximum size of batches returned in poll() with max.poll.records.

由于日志表明出现此问题是因为Kafka消费者未能提交。

以下是关于用例的一些详细信息:

  • 我有一个属于同一群组的主题My-Topic的多个消费者-Id my-consumer-group

  • 消费者使用来自Kafka的消息,应用业务逻辑并将处理过的数据存储在Cassandra

  • 从Kafka消费消息,应用业务逻辑然后将其保存到Cassandra 的过程大约需要10毫秒来自Kafka消耗的消息

我正在使用以下代码来创建Kafka-consumer bean

@Configuration
@EnableKafka
public class KafkaConsumer {
    @Value("${spring.kafka.bootstrap-servers}")
    private String brokerURL;

    @Value("${spring.kafka.session.timeout}")
    private int sessionTimeout;

    @Value("${spring.kafka.consumer.my-group-id}")
    private String groupId;

    @Value("${spring.kafka.listener.concurrency}")
    private int concurrency;

    @Value("${spring.kafka.listener.poll-timeout}")
    private int timeout;

    @Value("${spring.kafka.consumer.enable-auto-commit}")
    private boolean autoCommit;

    @Value("${spring.kafka.consumer.auto-commit-interval}")
    private String autoCommitInterval;

    @Value("${spring.kafka.consumer.auto-offset-reset}")
    private String autoOffsetReset;

    @Bean
    KafkaListenerContainerFactory<ConcurrentMessageListenerContainer<String, String>> kafkaListenerContainerFactory() {
        ConcurrentKafkaListenerContainerFactory<String, String> factory = new ConcurrentKafkaListenerContainerFactory<>();
        factory.setConsumerFactory(consumerFactory());
        factory.setConcurrency(concurrency);
        factory.getContainerProperties().setPollTimeout(timeout);
        return factory;
    }

    @Bean
    public ConsumerFactory<String, String> consumerFactory() {
        return new DefaultKafkaConsumerFactory<>(consumerConfigs());
    }

    @Bean
    public Map<String, Object> consumerConfigs() {
        Map<String, Object> propsMap = new HashMap<>();
        propsMap.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, brokerURL);
        propsMap.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, autoCommit);
        propsMap.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, autoCommitInterval);
        propsMap.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, sessionTimeout);
        propsMap.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
        propsMap.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
        propsMap.put(ConsumerConfig.GROUP_ID_CONFIG, groupId);
        propsMap.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, autoOffsetReset);
        return propsMap;
    }
} 

这些是我正在使用的kafka配置

spring.kafka.listener.concurrency=2
spring.kafka.listener.poll-timeout=3000
spring.kafka.consumer.auto-commit-interval=1000
spring.kafka.consumer.enable-auto-commit=true
spring.kafka.consumer.auto-offset-reset=earliest
spring.kafka.session.timeout=50000
spring.kafka.connection.timeout=10000
spring.kafka.topic.partition=5
spring.kafka.message.replication=2

我主要担心的是,属于同一个消费者群体的多个Kafka消费者在我的应用程序中重复读取消息,我必须避免重复输入数据库。

请您帮助我并查看我上面的Kafka配置和Kafka消费者代码,以便我可以避免重复阅读。

1 个答案:

答案 0 :(得分:0)

简单的答案是不要使用autoCommit - 它按计划提交。

相反,让容器进行提交;使用AckMode RECORD

但是你仍然应该使你的代码具有幂等性 - 总有可能重新发送;只是通过更可靠的提交策略,概率会更小。