Найти в Дзене
Цифровая Переплавка

Kafka на низкой нагрузке: почему это может быть болью и когда лучше выбрать что-то другое

Оглавление

На первый взгляд, кажется, что Apache Kafka способен закрыть любые потребности в очередях и обмене сообщениями: инструмент масштабируется до невероятных объемов и уже прочно укоренился в инфраструктуре сотен компаний. Но в своем блоге «Kafka at the low end: how bad can it get?» автор поднимает одну важную проблему: если вы используете Kafka при низких объемах трафика в роли очереди задач (job queue), то вас может ждать неприятный сюрприз. Давайте разберемся, что именно не так и почему эта «псевдоочередь» может работать совсем не так, как вы ожидаете.

«Несправедливое» распределение задач: как оно возникает

Если в классических системах очередей принято, что задачи распределяются более-менее равномерно по рабочим узлам (workers), то с Kafka, особенно при низком трафике, возникает так называемая «несправедливость» (unfairness). Это означает, что одна группа партиций может временно «застрять» у одного потребителя (consumer), тогда как другие простаивают в ожидании задач.

Как правило, Kafka распределяет партиции топика между всеми доступными consumer-процессами, и каждая партиция закрепляется за одним из них. Это работает отлично, когда задач много и они короткие: в сумме все выравнивается. Но стоит снизить интенсивность поступления сообщений, и случайность выбора партиций начнет играть с вами злую шутку.

Технические детали «провала»

Автор блога использует упрощенную формулу:

WorstCaseJobsPerConsumer = (Partitions / Consumers) * Producers

Она описывает, сколько задач может «упасть» на одного потребителя в самом плохом случае, прежде чем иные потребители получат хотя бы одну задачу. Представим ситуацию:

  • Имеется 16 партиций (Partitions),
  • Запущено 4 потребителя (Consumers),
  • Имеется 5 продюсеров (Producers), например, веб-серверы, которые при получении запроса создают задачу.

Подставляем числа:

WorstCaseJobsPerConsumer = (16 / 4) * 5 = 20

Это значит, что 20 задач могут все целиком оказаться у одного единственного worker, пока остальные 3 будут скучать без дела. Если эти задачи, к тому же, обрабатываются долго, то «неудачный» воркер (worker) будет заблокирован и будет долго «переваривать» данные, тогда как другие потребители останутся не у дел.

Почему это больно при низком трафике

Когда количество задач невелико — скажем, «случайные 15 или 20 штук в час» — такая ситуация может повторяться относительно часто. Тогда:

⚠️ Один потребитель завален
Он берется за все пришедшие задачи разом, а у него перед этим нет очереди.

⚠️ Остальные простаивают
Вы платите (времени или ресурсов) за большее количество worker-процессов, чем реально нужно, а толку нет — ведь их никто не нагружает.

⚠️ Простои пользователей
Если эти задачи выполняются длительно (например, формирование PDF-отчета на 5-10 минут), то пользователь, которому «не повезло» оказаться в очереди на том самом «захлебнувшемся» потребителе, ждет в несколько раз дольше.

Личное мнение: когда Kafka все же работает «приемлемо»?

На мой взгляд, Kafka — это все еще великолепный инструмент, но друг для больших данных и быстрого потока. Когда у вас:

💥 Тысячи (или миллионы) сообщений в секунду:
Тогда задержки и «несправедливости» сглаживаются, потому что система автоматически перераспределяет нагрузку, а «случайности» быстро нивелируются большим объемом данных.

Критична горизонтальная масштабируемость:
Kafka умеет «шардировать» сообщения по партициям, хранить их на кластере брокеров, гнать поток на сотни и тысячи consumer-процессов. Ни один RabbitMQ так легко не сможет достичь подобных объемов.

Однако если в вашем проекте:

🐢 Низкий трафик (условно, десятки-сотни задач в сутки):
Kafka может обернуться избыточным и непредсказуемым решением. Быть может, стоит присмотреться к легковесным очередям типа RabbitMQ, Redis Streams или Amazon SQS?

🔄 Критично справедливое и предсказуемое распределение:
Если вам важна именно выверенная нагрузка — одна задача в один worker, следующая в другой и так далее — используйте классические брокеры очередей, которые «заточены» под это.

А что впереди? Надежда на Queues for Kafka (KIP-932)

В новости упоминается, что готовящийся KIP-932 (Queues for Kafka - очереди для Кафка) может ослабить многие ограничения. Это позволит работать с топиками (или специальными «очередями» внутри Kafka) без столь громоздкой механики партиций и перераспределения. Тогда, возможно, описанные проблемы уйдут в прошлое или хотя бы станут менее острыми. Но на момент написания (февраль 2025 года) этот стандарт еще не полностью внедрен.

Когда имеет смысл запускать Kafka при низкой нагрузке.

Можно сформулировать несколько ситуаций:

🔎 Случай «прототипирования»
Если вы уже
все равно подняли Kafka-кластер для других, высоконагруженных сервисов, и вам нужно отправить «пять задачек раз в день», то можно не городить еще один сервис очередей. Но будьте готовы к неожиданностям в распределении!

🤷 «Лень» поддерживать новую технологию
Бывает, что команда предпочитает не добавлять RabbitMQ или аналог, потому что «и так уже хватает». Тогда Kafka становится единым решением для всего. Если вы осознаете, что задачи будут иногда «кучковаться», и вас это устраивает, — почему бы и нет.

Ссылка по теме

Если вам нужен действительно равномерный и предсказуемый процессинг задач при малых объемах, лучше выбрать классический брокер очередей (RabbitMQ, ActiveMQ, Redis Lists). Kafka — это про потоки данных на скорости света, про миллионы событий, которые нужно устойчиво хранить и обрабатывать. Для «простой очереди на 15 пользователей» это зачастую из пушки по воробьям: красиво, современно, но рискованно и не всегда эффективно.

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