Каковы основные преимущества и недостатки Apache Kafka?

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

Ответ

Преимущества Apache Kafka:

  • Высокая пропускная способность и низкая задержка: Способна обрабатывать миллионы сообщений в секунду благодаря последовательному I/O и пакетной обработке.
  • Масштабируемость и отказоустойчивость: Легко масштабируется горизонтально добавлением брокеров. Данные реплицируются между брокерами, обеспечивая устойчивость к сбоям.
  • Долговременное хранение: Сообщения хранятся на диске с настраиваемым временем жизни (TTL), что позволяет повторно потреблять данные.
  • Поддержка потоковой обработки: Интеграция с Kafka Streams, Flink, Spark для обработки данных в реальном времени.
  • Высокая параллельность: Партиционирование топиков позволяет множеству потребителей работать параллельно.

Недостатки Apache Kafka:

  • Операционная сложность: Требует настройки и администрирования кластера (ZooKeeper, брокеры), что увеличивает overhead.
  • Сложность конфигурации: Множество параметров настройки для тюнинга производительности и надёжности.
  • Отсутствие встроенного мониторинга: Необходимо использовать сторонние инструменты (например, JMX, Prometheus, Confluent Control Center).
  • Ограниченные возможности запросов: Не является БД; поиск по ключу эффективен, но поиск по значению требует сторонних решений (KSQL, индексации).

Пример отправки сообщения (Producer API):

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)) {
    // Асинхронная отправка с callback для обработки результата
    producer.send(new ProducerRecord<>("orders", "order-123", "{...}"),
                  (metadata, exception) -> {
                      if (exception == null) {
                          System.out.println("Сообщение записано в партицию: " + metadata.partition());
                      }
                  });
}