web-dev-qa-db-ja.com

春Kafka非同期送信呼び出しブロック

私はSpring-Kafkaバージョン1.2.1を使用していて、Kafkaサーバーがダウン/到達不能の場合、非同期送信呼び出しがしばらくブロックします。TCPタイムアウトコードは次のようなものです:

ListenableFuture<SendResult<K, V>> future = kafkaTemplate.send(topic, key, message);
future.addCallback(new ListenableFutureCallback<SendResult<K, V>>() {
    @Override
    public void onSuccess(SendResult<K, V> result) {
        ...
    }

    @Override
    public void onFailure(Throwable ex) {
        ...
    }
});

私はSpring-Kafkaコードを非常に簡単に調べましたが、kafkaクライアントライブラリにタスクを渡し、コールバックの相互作用を将来のオブジェクトの相互作用に変換しているようです。 kafkaクライアントライブラリ、コードはより複雑になり、すべてを理解するのに時間はかかりませんでしたが、リモートコール(少なくともメタデータ)を実行している可能性があります)同じスレッド。

ユーザーとして、リモートkafkaサーバーにアクセスできない場合でも、futureを返すSpring-Kafkaメソッドがすぐに戻ることを期待していました。

私の理解が間違っているか、これがバグであるかどうかの確認は歓迎されます。今のところ、私はそれを私の最後で非同期にしてしまいました。

もう1つの問題は、Spring-Kafkaのドキュメントに、最初は同期および非同期の送信メソッドが提供されていると記載されていることです。フューチャーを返さないメソッドは見つかりませんでした。おそらくドキュメントの更新が必要です。

必要に応じて、さらに詳しい情報を提供させていただきます。ありがとう。

14

構成クラスの@EnableAsyncアノテーションに加えて、このコードを呼び出すメソッドでは@Asyncアノテーションを使用する必要があります。

http://www.baeldung.com/spring-async

ここにいくつかのコードの断片があります。 Kafkaプロデューサー設定:

@EnableAsync
@Configuration
public class KafkaProducerConfig {

    private static final Logger LOGGER = LoggerFactory.getLogger(KafkaProducerConfig.class);

    @Value("${kafka.brokers}")
    private String servers;

    @Bean
    public Map<String, Object> producerConfigs() {
        Map<String, Object> props = new HashMap<>();
        props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, servers);
        props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
        props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
        return props;
    }

    @Bean
    public ProducerFactory<String, GenericMessage> producerFactory(ObjectMapper objectMapper) {
        return new DefaultKafkaProducerFactory<>(producerConfigs(), new StringSerializer(), new JsonSerializer(objectMapper));
    }

    @Bean
    public KafkaTemplate<String, GenericMessage> kafkaTemplate(ObjectMapper objectMapper) {
        return new KafkaTemplate<String, GenericMessage>(producerFactory(objectMapper));
    }

    @Bean
    public Producer producer() {
        return new Producer();
    }
}

そしてプロデューサー自体:

public class Producer {

    public static final Logger LOGGER = LoggerFactory.getLogger(Producer.class);

    @Autowired
    private KafkaTemplate<String, GenericMessage> kafkaTemplate;

    @Async
    public void send(String topic, GenericMessage message) {
        ListenableFuture<SendResult<String, GenericMessage>> future = kafkaTemplate.send(topic, message);
        future.addCallback(new ListenableFutureCallback<SendResult<String, GenericMessage>>() {

            @Override
            public void onSuccess(final SendResult<String, GenericMessage> message) {
                LOGGER.info("sent message= " + message + " with offset= " + message.getRecordMetadata().offset());
            }

            @Override
            public void onFailure(final Throwable throwable) {
                LOGGER.error("unable to send message= " + message, throwable);
            }
        });
    }
}
11
Jorge C

念のために。 @EnableAsyncアノテーションが適用されていますか?これが、Future <>の動作を指定するための鍵になると言いたい

2
Chad

最善の解決策は、プロデューサーのレベルで「コールバック」リスナーを追加することです。

@Bean
public KafkaTemplate<String, WebUserOperation> operationKafkaTemplate() {
    KafkaTemplate<String, WebUserOperation> kt = new KafkaTemplate<>(operationProducerFactory());
    kt.setProducerListener(new ProducerListener<String, WebUserOperation>() {

        @Override
        public void onSuccess(ProducerRecord<String, WebUserOperation> record, RecordMetadata recordMetadata) {
            System.out.println("### Callback :: " + recordMetadata.topic() + " ; partition = " 
                    + recordMetadata.partition()  +" with offset= " + recordMetadata.offset()
                    + " ; Timestamp : " + recordMetadata.timestamp() + " ; Message Size = " + recordMetadata.serializedValueSize());
        }

        @Override
        public void onError(ProducerRecord<String, WebUserOperation> producerRecord, Exception exception) {
            System.out.println("### Topic = " + producerRecord.topic() + " ; Message = " + producerRecord.value().getOperation());
            exception.printStackTrace();
        }
    });
    return kt;
}
0
Arpit Gupta