【问题标题】:No pending reply: ConsumerRecord没有待处理的回复:ConsumerRecord
【发布时间】:2019-05-14 02:51:30
【问题描述】:

我正在尝试使用 ReplyingKafkaTemplate,但我会间歇性地看到下面的消息。

没有待处理的回复:ConsumerRecord(topic = request-reply-topic, partition = 8,offset = 1,CreateTime = 1544653843269,序列化键 大小 = -1,序列化值大小 = 1609,标题 = RecordHeaders(headers = [RecordHeader(key = kafka_correlationId, value = [-14, 65, 21, -118, 70, -94, 72, 87, -113, -91, 92, 72, -124, -110, -64, -94])], isReadOnly = false) ,key = null,correlationId:[-18271255759235816475365319231847350110],可能超时,或者使用 共享回复主题

这将源于下面的代码

RequestReplyFuture<K, V, R> future = this.futures.remove(correlationId);
if (future == null) {
  if (this.sharedReplyTopic) {
    if (this.logger.isDebugEnabled()) {
      this.logger.debug(missingCorrelationLogMessage(record, correlationId));
    }
  }
  else if (this.logger.isErrorEnabled()) {
    this.logger.error(missingCorrelationLogMessage(record, correlationId));
  }
}

但只是间歇性地发生

我还将共享回复主题设置为 false,如下所示,并尝试强制延长超时时间

ReplyingKafkaTemplate<String, Object, Object> replyKafkaTemplate = new ReplyingKafkaTemplate<>(pf, container);
        replyKafkaTemplate.setSharedReplyTopic(false);
        replyKafkaTemplate.setReplyTimeout(10000);
        return replyKafkaTemplate;

我的容器如下

@Bean
public KafkaListenerContainerFactory<ConcurrentMessageListenerContainer<String, Object>> kafkaListenerContainerFactory() {
    ConcurrentKafkaListenerContainerFactory<String, Object> factory = new ConcurrentKafkaListenerContainerFactory<>();
    factory.setConsumerFactory(consumerFactory());

    factory.setBatchListener(false);
    factory.getContainerProperties().setPollTimeout(1000);
    factory.getContainerProperties().setIdleEventInterval(10000L);
    factory.setConcurrency(3);
    factory.setReplyTemplate(kafkaTemplate());
    return factory;
}

【问题讨论】:

    标签: java apache-kafka spring-kafka


    【解决方案1】:

    在消费者上使用属性 @Header (KafkaHeaders.CORRELATION_ID) 修复了问题

    @KafkaListener(topics = "${kafka.topic.model}")
    @SendTo("replymodeltopic")
    @Override
    public Model receive(ConsumerRecord<String, model> record, @Header(KafkaHeaders.CORRELATION_ID) byte[] correlation) { 
        record.headers().add(KafkaHeaders.CORRELATION_ID, correlation);
        return record.value();
    }
    

    在我的配置上我有

    @Configuration
    @EnableKafka
    public class ReceiverConfig {
    
        @Value("${kafka.bootstrap-servers}")
        private String bootstrapServers;
    
        @Value("${kafka.tunnel.group}")
        private String tunnelGroup;
    
        @Value("${kafka.topic.json.reply}")
        private String jsonTopicReply;
    
        @Bean
        public Map<String, Object> consumerConfigs() {
            Map<String, Object> props = new HashMap<>();
            props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
            props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
            props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
            props.put(ConsumerConfig.GROUP_ID_CONFIG, tunnelGroup);
    
            return props;
        }
    
        @Bean
        public Map<String, Object> producerConfigs() {
            Map<String, Object> props = new HashMap<>();
            props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
            props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
            props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class);
            return props;
        }
    
        @Bean
        public ConsumerFactory<String, Model> consumerFactory() {
            return new DefaultKafkaConsumerFactory<>(consumerConfigs(), new StringDeserializer(), new JsonDeserializer<>(Model.class));
        }
    
        @Bean
        public ConcurrentKafkaListenerContainerFactory<String, Model> kafkaListenerContainerFactory() {
            ConcurrentKafkaListenerContainerFactory<String, Model> factory = new ConcurrentKafkaListenerContainerFactory<>();
            factory.setConsumerFactory(consumerFactory());
            factory.setReplyTemplate(replyTemplate());
            return factory;
        }
    
        @Bean
        public ProducerFactory<String, Model> producerFactory() {
            return new DefaultKafkaProducerFactory<>(producerConfigs());
        }
    
        @Bean
        public KafkaTemplate<String, Model> replyTemplate() {
            KafkaTemplate<String, Model> kafkaTemplate = new KafkaTemplate<>(producerFactory());
            kafkaTemplate.setDefaultTopic(jsonTopicReply);
            return kafkaTemplate;
        }
    
    }
    

    【讨论】:

      【解决方案2】:

      如果是断断续续的,很可能是回复的时间过长。消息似乎很清楚

      可能超时,或使用共享回复主题

      每个客户端实例都必须使用自己的回复主题或专用分区。

      编辑

      如果收到的消息的相关 id 与 this.futures 中当前的条目不匹配(待回复),您将获得日志。这只会在以下情况下发生:

      1. 请求超时(在这种情况下会有相应的 WARN 日志)。
      2. 模板被 stop()ped (在这种情况下 this.futures 被清除)。
      3. 由于某种原因(不应该发生)重新发送了已处理的回复。
      4. 在将密钥添加到 this.futures 之前收到回复(不可能发生,因为它是在发送()记录之前插入的)。
      5. 服务器端对同一请求发送 2 个或多个回复。
      6. 其他一些应用程序正在向同一个回复主题发送数据。如果您可以使用 DEBUG 日志记录重现它,这将有所帮助,因为我们也会在发送时记录关联密钥。

      【讨论】:

      • 感谢我的日志中的响应,从我的日志中超时发生得太快我看到消费者在 2018-12-13 02:37:46,713| 收到请求信息 | org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1 和几毫秒后的超时 2018-12-13 02:37:46,839|错误 |回复容器-C-1 |工业电脑 | ReplyingKafkaTemplate -309 |没有待处理的回复:ConsumerRecord
      • sharedReplyTopic 应该是 true 如果您有多个客户端实例;默认为假;将其设置为 true 会将错误日志更改为调试日志。我看到您在服务器端有一个侦听器容器;听者是什么?除非模板接收到带有无法识别的相关 id 标头值的消息,否则不可能出现此错误。
      • 现在我有一个客户端实例,所以我猜它已经在错误日志中了。当您说无法识别时,您的意思是已损坏,因为它记录如下with correlationId: [-25828241019201938464047331559992730192], perhaps timed out, or using a shared reply topic
      • 谢谢 Gary 问题是 #2 我使用了不正确的回复模板将我的容器配置更改为 factory.setReplyTemplate(replyKafkaTemplate(producerFactory(), replyContainer(consumerFactory()))); 并且错误消失了不确定您是否需要修改答案,我对此很陌生!
      • 我将最后 2 个 cmets 移至答案;您根本不应该在服务器端使用回复模板。回复模板是请求/回复场景的客户端工件。在服务器端,您只需在工厂的replyTemplate 属性中使用一个简单的KafkaTemplate。容器接收请求并使用模板发送回复。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-01
      • 2020-12-18
      • 1970-01-01
      • 2018-01-02
      相关资源
      最近更新 更多