Что такое consumer group в Kafka и как она помогает разделять нагрузку между потребителями?
Что проверяют
Понимаете ли вы, что единица параллелизма в Kafka это партиция, а не потребитель. Следом обычно спрашивают, что будет при трёх партициях и пяти потребителях, что происходит при ребалансе и почему сообщения всё-таки обрабатываются дважды.
Как отвечать
Consumer group это набор потребителей с одинаковым group.id. Каждая партиция топика в любой момент закреплена ровно за одним участником группы, а один участник может читать несколько партиций. Отсюда правила:
- параллелизм ограничен партициями: при 6 партициях и 3 потребителях у каждого по две, при 8 потребителях двое простаивают;
- порядок: гарантирован только внутри партиции, поэтому связанные события шлют с одним ключом;
- разные группы независимы: каждая получает все сообщения со своими смещениями, так один поток событий читают и биллинг, и аналитика;
- смещения: группа коммитит позицию в служебный топик
__consumer_offsets, по умолчаниюenable.auto.commit=trueраз в 5 секунд.
Ребаланс запускается, когда участник приходит, уходит или не вызывает poll() дольше max.poll.interval.ms (по умолчанию 5 минут). Старый eager-протокол останавливал всю группу, CooperativeStickyAssignor переносит только нужные партиции. В Kafka 4.0 стал общедоступным протокол из KIP-848 (group.protocol=consumer), где назначение считает брокер. Подам в Kubernetes помогает статическое членство через group.instance.id.
KafkaConsumer не потокобезопасен: один экземпляр на поток. В Spring Kafka @KafkaListener(groupId = "billing", concurrency = "3") поднимет три потребителя в одной группе.
Где спотыкаются
Говорят «каждое сообщение обработается ровно один раз». Гарантия по умолчанию at-least-once: после ребаланса новый владелец партиции перечитает всё с последнего закоммиченного смещения. Спасает идемпотентная обработка, а для цепочки Kafka в Kafka есть транзакции.
Добавляют потребителей, чтобы разогнать обработку, не глядя на число партиций. Лишние просто сидят без работы.
Делают долгую обработку в poll-цикле. Превышение max.poll.interval.ms выкидывает потребителя из группы, партиции уходят другому, и начинаются дубли.