Блокируется ли поток при отправке или получении сообщений из Kafka?

«Блокируется ли поток при отправке или получении сообщений из Kafka?» — вопрос из категории Брокеры сообщений, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

По умолчанию Kafka работает неблокирующе, но поведение можно настроить в зависимости от требований.

1. Producer (отправка сообщений):

// АСИНХРОННАЯ отправка (не блокирует поток)
ProducerRecord<String, String> record = new ProducerRecord<>("topic", "key", "value");
producer.send(record, (metadata, exception) -> {
    // Callback выполнится при получении подтверждения от брокера
    if (exception != null) {
        logger.error("Ошибка отправки", exception);
    } else {
        logger.info("Отправлено в partition {} offset {}", 
                   metadata.partition(), metadata.offset());
    }
});
// Продолжение выполнения кода без ожидания

// СИНХРОННАЯ отправка (блокирует поток до подтверждения)
try {
    RecordMetadata metadata = producer.send(record).get(); // БЛОКИРУЮЩИЙ ВЫЗОВ
    System.out.println("Отправлено: " + metadata.offset());
} catch (InterruptedException | ExecutionException e) {
    e.printStackTrace();
}

2. Consumer (получение сообщений):

// НЕБЛОКИРУЮЩИЙ poll() с таймаутом
ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
if (records.isEmpty()) {
    // Нет сообщений - продолжаем работу
    return;
}
for (ConsumerRecord<String, String> record : records) {
    processMessage(record.value());
}

3. Современные реактивные подходы (Spring Kafka):

@Bean
public ReactiveKafkaConsumerTemplate<String, String> reactiveConsumer() {
    return new ReactiveKafkaConsumerTemplate<>(receiverOptions);
}

// Реактивная обработка без блокировки
reactiveConsumer.receive()
    .doOnNext(record -> {
        System.out.println("Получено: " + record.value());
        record.receiverOffset().acknowledge();
    })
    .subscribe();

Рекомендации:

  • Используйте асинхронную отправку с callback для максимальной производительности
  • Настройте acks, retries, max.in.flight.requests.per.connection для баланса между надежностью и скоростью
  • Для потребителей используйте максимально короткие таймауты в poll()
  • Рассмотрите реактивные реализации (Kafka Streams, Spring Reactor Kafka) для сложных пайплайнов обработки