Можно ли предотвратить ребалансировку при отвале консьюмера в Kafka?
Что проверяют
Понимаете ли вы, из-за чего вообще случается ребалансировка и какими настройками управляется группа консьюмеров. Вопрос отделяет тех, кто читал про group.id, от тех, кто разбирал растущий лаг на проде.
Как отвечать
Полностью отключить ребалансировку при настоящем отвале нельзя: это механизм, которым группа перераспределяет партиции. Но можно добиться, чтобы короткая пропажа консьюмера её не вызывала, а сама ребалансировка не останавливала всю группу.
- статическое членство: задать
group.instance.idи разумныйsession.timeout.ms. Перезапуск экземпляра не выкидывает участника из группы, координатор ждёт возвращения того же идентификатора и отдаёт ему те же партиции; - кооперативный протокол:
CooperativeStickyAssignorвместо назначения по диапазонам. Партиции переезжают по одной, остальные консьюмеры продолжают читать, вместо того чтобы всей группой отдать всё и забрать заново; - ручное назначение:
assign()вместоsubscribe()группу не образует вовсе, но тогда распределение партиций и отказоустойчивость целиком на вас.
Отдельно скажите, что чаще консьюмер отваливается не по сети, а по max.poll.interval.ms: обработка пачки заняла больше таймаута, и координатор счёл его мёртвым. Лечится это уменьшением max.poll.records или выносом долгой работы из потока опроса.
Где спотыкаются
Крутят session.timeout.ms вверх и считают вопрос закрытым. Растёт только время, за которое группа заметит настоящую смерть консьюмера, а лаг всё это время копится. Значение вдобавок ограничено брокерскими настройками минимума и максимума.
Второе: путают сердцебиение и опрос. Heartbeat шлёт фоновый поток, и он продолжает идти, пока обработка висит в вашем коде. Именно поэтому таймаут на опрос вынесен в отдельный параметр.
Третье: забывают про коммит офсетов. При ребалансировке незакоммиченные офсеты означают повторную обработку, поэтому обработчик обязан быть идемпотентным, а ConsumerRebalanceListener нужен, чтобы закоммитить перед отдачей партиций.