Почему в Apache Kafka не рекомендуется назначать несколько Consumer’ов на одну партицию?

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

Ответ

В модели Kafka один потребитель (Consumer) читает сообщения строго из одной партиции. Назначение нескольких потребителей на одну партицию нарушает базовые гарантии Kafka и приводит к проблемам.

Почему это плохая практика:

  1. Нарушение гарантии порядка: Kafka гарантирует порядок доставки сообщений только в пределах одной партиции. Если два независимых потребителя читают одну партицию, они будут конкурировать за смещения (offsets), и сообщения будут обрабатываться в произвольном порядке.

  2. Дублирование обработки: Потребители не знают о смещениях друг друга. Сообщение, прочитанное и обработанное одним потребителем, может быть снова прочитано другим, если первый не успел зафиксировать смещение.

  3. Отсутствие балансировки нагрузки: Потребители не скоординированы. Один может прочитать и обработать все сообщения, пока другой простаивает.

Правильный подход: Consumer Groups

  • Потребители объединяются в Consumer Group (указывается в group.id).
  • Каждая партиция топика назначается ровно одному потребителю внутри группы.
  • При добавлении или удалении потребителя из группы происходит ребалансировка партиций.

Пример корректной настройки Consumer Group:

Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("group.id", "order-processors"); // Имя группы потребителей
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("enable.auto.commit", "true"); // Автоматическая фиксация смещений

KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
consumer.subscribe(Arrays.asList("orders-topic")); // Подписка на топик

// Для топика с 4 партициями и группой из 2 потребителей:
// - Consumer 1 получит партиции 0 и 1.
// - Consumer 2 получит партиции 2 и 3.
// Каждое сообщение будет обработано ровно один раз в порядке его поступления в партицию.

Вывод: Для масштабирования обработки увеличивайте количество партиций в топике и добавляйте потребителей в одну группу, а не назначайте несколько потребителей на одну партицию.