В каких случаях стоит использовать Apache Kafka, а в каких нет?

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

Ответ

Apache Kafka — распределенная потоковая платформа. Её применение должно быть обосновано архитектурными требованиями.

✅ Когда Kafka — хороший выбор:

  • Обработка потоков событий в реальном времени: логи, телеметрия, клики.
  • Высокая пропускная способность и горизонтальное масштабирование.
  • Требуется гарантированная доставка и отказоустойчивость (репликация).
  • Архитектура на основе событий (Event-Driven Architecture): декoupling сервисов.
  • Необходимость повторной обработки данных (хранение сообщений длительное время).

❌ Когда Kafka — избыточна или не подходит:

  • Простые синхронные RPC-вызовы между двумя сервисами (используйте REST/gRPC).
  • Очереди задач (Job Queues) с одним потребителем на сообщение (рассмотрите RabbitMQ).
  • Сценарии с очень низкой нагрузкой, где сложность администрирования Kafka не окупается.
  • Требуется строгий глобальный порядок сообщений (Kafka гарантирует порядок только в пределах партиции).
  • Транзакции, затрагивающие несколько источников данных (Sagas поверх Kafka сложны).

Пример Producer/Consumer:

// Producer
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");

try (Producer<String, String> producer = new KafkaProducer<>(props)) {
    producer.send(new ProducerRecord<>("user-events", "user123", "{"action":"login"}"));
}

// Consumer
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("group.id", "my-group");
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");

try (KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props)) {
    consumer.subscribe(List.of("user-events"));
    while (true) {
        ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
        for (ConsumerRecord<String, String> record : records) {
            System.out.println("Processed: " + record.value());
        }
    }
}

Выбор инструмента должен соответствовать задаче.