Консьюмеры и группы: параллельное чтение
Урок про сторону чтения: как несколько консьюмеров делят работу, не наступая друг другу на ноги.
Группа консьюмеров (consumer group) — набор консьюмеров с общим
group.id, между которыми Kafka распределяет партиции топика так, что каждую партицию читает ровно один член группы.
Зачем это нужно
Один консьюмер не справится с потоком в миллионы событий. Группа позволяет масштабировать чтение: запускаете N экземпляров одного сервиса с общим group.id, и Kafka сама раздаёт им партиции. Каждое событие обработает ровно один экземпляр — работа делится без дублирования.
Распределение партиций
Топик 4 партиции, группа "billing" из 2 консьюмеров: C1 <-- P0, P1 C2 <-- P2, P3 Добавили C3: C1 <-- P0 C2 <-- P1, P2 C3 <-- P3 (партиции перераспределились -- это ребаланс)
Разные группы читают топик независимо: у каждой свой набор оффсетов. Сервис аналитики и сервис биллинга с разными group.id оба прочитают все события — это broadcast между группами и распределение внутри группы.
Ребалансировка
Ребаланс — перераспределение партиций при изменении состава группы: консьюмер вошёл, вышел или «завис» и был исключён. Координатор группы (один из брокеров) переназначает партиции. На время ребаланса чтение приостанавливается — это его цена.
Пример конфигурации консьюмера
bootstrap.servers=localhost:9092
group.id=billing
key.deserializer=org.apache.kafka.common.serialization.StringDeserializer
value.deserializer=org.apache.kafka.common.serialization.StringDeserializer
max.poll.records=500
session.timeout.ms=10000
Как работает под капотом
Каждый консьюмер шлёт координатору периодические heartbeat'ы. Если за session.timeout.ms heartbeat не пришёл, координатор считает консьюмера мёртвым и запускает ребаланс. Назначение партиций считает assignor (стратегия вроде range, round-robin или cooperative-sticky). Современная «кооперативная» ребалансировка отдаёт только часть партиций, не останавливая всю группу целиком (incremental cooperative rebalancing), — это резко снижает «паузы мира» по сравнению со старым подходом «отобрать всё и раздать заново».
Частые ошибки
- Долгая обработка в poll-цикле. Если между вызовами poll проходит больше
max.poll.interval.ms, консьюмера сочтут зависшим и исключат — ребаланс-шторм. - Больше консьюмеров, чем партиций. Лишние простаивают (см. урок про партиции).
- Один group.id на несоединённые сервисы. Они начнут «воровать» партиции друг у друга, думая, что они одна группа.
Итоги
- Внутри группы каждую партицию читает ровно один консьюмер — работа делится без дублей.
- Разные группы читают топик независимо, со своими оффсетами (broadcast между группами).
- Ребаланс перераспределяет партиции при смене состава; кооперативный режим снижает паузы.