简体   繁体   English

卡夫卡消费者正在重用主题中的消息

[英]Kafka consumer is reconsuming messages from topic

The Kafka consumer in our Java application was re-consuming messages from the topic for some reason. 我们的Java应用程序中的Kafka使用者出于某种原因重用了该主题中的消息。

Producer send messages to a topic which has four partitions. 生产者将消息发送到具有四个分区的主题。 We have one consumer consumes messages from this topic. 我们有一个使用者正在消费来自此主题的消息。 The application runs all the time in weekdays exception weekend:It won't call poll method during the weekend. 该应用程序在工作日(周末除外)的所有时间运行:在周末不会调用轮询方法。
Consumer config: auto commit, auto commit time is 5s (default). 使用者配置:自动提交,自动提交时间为5秒(默认)。

The application ran fine until a Sunday when it resumed to call poll method again. 该应用程序可以正常运行,直到周日再次恢复调用轮询方法为止。 We saw million of messages were polled from the topic. 我们看到从该主题轮询了数百万条消息。 The consumer was basically polling all the messages from the topic. 消费者基本上是在轮询来自该主题的所有消息。 When comparing the new offset with the offset before it stopped for the weekend. 将新偏移量与周末停止之前的偏移量进行比较时。 The new offset is much smaller, it was like reset to very low numbers for all of the four partitions. 新的偏移量要小得多,就像对所有四个分区重置为非常小的数字一样。

We don't know what happened in the consumer side as it is not calling poll method, so no log message was printed. 我们不知道用户端发生了什么,因为它没有调用轮询方法,因此没有打印日志消息。 We checked kafka server log, but we found nothing. 我们检查了kafka服务器日志,但未找到任何内容。

Does anyone see this before? 有人看过吗? Would the consumer be misconfigured? 消费者的配置是否会错误?

    <spring.kafka.version>1.1.2.RELEASE</spring.kafka.version>
     ... 
  <bean id="defaultKafkaConsumer"
        class="org.apache.kafka.clients.consumer.KafkaConsumer">
        <constructor-arg>  
            <map>
                <entry key="bootstrap.servers"  value="${kafka.bootstrap.servers}"></entry>
                <entry key="max.block.ms"  value="5000"></entry>
                <entry key="group.id"  value="kafkaconnect.tca"></entry>
                <entry key="auto.offset.reset" value="earliest"></entry>
                <entry key="key.deserializer"  value="org.apache.kafka.common.serialization.StringDeserializer"></entry>
                <entry key="value.deserializer"  value="org.apache.kafka.common.serialization.StringDeserializer"></entry>
            </map>  
        </constructor-arg>  
    </bean>

    getKafkaConsumer().subscribe(Arrays.asList(getKafkaTopic()));
            // set up the polling task
            handler = timer.scheduleAtFixedRate(new Runnable() {
                public void run() {
                    try {
                        processPoll();
                    } catch (Throwable t) {
                        LOG.error(String.format("error processing poll for inet: %s, details: %s - %s", getId(), t.getMessage(), t.getCause()), t);
                    }
                }
            }, 3, 3, TimeUnit.MILLISECONDS);



   processPoll() Method: destination will not be ready during the weekend.
   try {
            if (!isDestinationReady()) {
                if (destinationIgnoreCnt++ ==0) {
                    LOG.warn(String.format("outbound destination session is not ready - trying: %s/%s",destinationIgnoreCnt,destinationwaitingloop));
                } else if ((destinationIgnoreCnt++ % destinationwaitingloop) == 0) {
                    LOG.warn(String.format("outbound destination session is not ready - trying %s/%s", destinationIgnoreCnt,destinationwaitingloop));
                    destinationIgnoreCnt = 1;
                }
                messageIgnoreCnt = 0;
                return;
            }
            if(!isDestinationOpen()) {
                if (destinationIgnoreCnt++ ==0) {
                    LOG.error(String.format("outbound destination is not opended - trying:%s/%s.", destinationIgnoreCnt,destinationwaitingloop) );
                } else if ((destinationIgnoreCnt++ % destinationwaitingloop) == 0) {
                    LOG.error(String.format("outbound destination is not opended - trying %s/%s.", destinationIgnoreCnt,destinationwaitingloop));
                    destinationIgnoreCnt = 1;
                }
                messageIgnoreCnt = 0;
                return;
            }

            if (messageIgnoreCnt++ == 0) {
                LOG.info(String.format("kafka poller started. poll interval %s wait: %s", pollingInterval, 60000));
            } else if ((messageIgnoreCnt++ % 30) == 0) {// approximately 30mins
                LOG.info(String.format("kafka poller started. poll interval %s wait %s", pollingInterval, 60000));
                messageIgnoreCnt = 1;
            }

            if (getKafkaConsumer() == null) {
                LOG.critical("KafkaListener consumer is null");
                return;
            }

            ConsumerRecords<String, String> records = getKafkaConsumer().poll(60000);
            if (records == null || records.isEmpty()) {
                LOG.debug("zero records received from Kafka");
                return;
            }
            for (ConsumerRecord<String, String> record : records) {
                LOG.info(String.format("consuming from topic =  %s ", record.toString()));
                try {
                    String jsonMsg = record.value();

                    DirectBatchRequest payload = JacksonUtilities.getObjectMapper().readValue(jsonMsg, DirectBatchRequest.class);

                    if (payload != null) {
                        LOG.info(String.format("Got it reportId:%s", payload.getDestinationId()));
                        if(payload.getDestinationId() == 0) {
                            LOG.info(String.format("Applying default destination desk:%s", defaultDeskId));
                            payload.setDestinationId(defaultDeskId);
                        }
                        List<RequestEntryType> requestEntryTypeList = ((StreamDirectRequest) payload).getRequestList();
                        LOG.info(String.format("Processing size: %s" , requestEntryTypeList.size()) );
                        processRequest((StreamDirectRequest) payload);  //async call
                        LOG.info(String.format("Processing size: %s sent to Steam" , requestEntryTypeList.size()) );    
                    }
                } catch (Throwable t) {
                    LOG.error(String.format("KafkaListener JSON%s conversion error %s", record, t.getMessage()));
                }

            }

        } catch (Throwable t) {
            LOG.error(String.format("KafkaListener exception %s", t.getMessage()));

        }

Kafka by default removes the offsets after offsets.retention.minutes if there is no activity from the consumer group. 卡夫卡在默认情况下删除后的偏移量offsets.retention.minutes如果没有从消费者群体活动。 The default retention period is 1440 minutes(1 day). 默认保留期为1440分钟(1天)。

In your case, since the consumer-group is down for the weekend, offset is reset. 在您的情况下,由于消费者组在周末休息,因此偏移被重置。

See https://kafka.apache.org/documentation/#brokerconfigs 参见https://kafka.apache.org/documentation/#brokerconfigs

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM