Зачем вообще использовать брокеры очередей?

Вот возьмем для примера простую задачку: пользователю нужно отправлять письма-уведомления, допустим о сделанной покупке в магазине.

Стандартный способ решить задачу: обработчик пользовательского запроса создает в sql-базе таск на отправку письма со статусом "new" и возвращает пользователю ответ. Далее некий воркер читает новые таски из базы, обрабатывает их (в нашем случае формирует и отсылает письмо) выставляет таску статус "done". Перед обработкой можно еще статус "in_progress" поставить, если хендлеров несколько или это, допустим, запускаемые по крону скрипты, но это уже детали реализации, не будем о них.

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

И вроде как напрашивается идея использовать брокер очередей, например тот же RabbitMQ. Тогда схема становится такой: обработчик пользовательского запроса все еще создает в sql-базе таск на отправку письма со статусом "new", так как эта важная для бизнеса операция и нужно контролировать отправку писем, а брокеры очередей в случае падения теряют данные. Хендлер так же каждые 5 секунд опрашивает, но уже не базу, а брокер очередей, на предмет появления новых тасков. Выполняет таск и ставит в базе данных статус "done".

Получаем те же яица, только в профиль. Из плюсов только то, что нам больше не нужен статус "in_progress", так как за тем, чтоб таск не выполнялся дважды будет следить сам брокер. Но преимущество сомнительное.

Можно немного изменить модель: хендлер не будет писать в базу статус, а будет складывать отработанные таски в отдельную очередь, из которой их будет забирать второй хендлер, вся суть которого будет состоять в проставлении выполненyым таскам статуса "done". Из преимуществ - первому хендлеру не нужно подключение к базе, все данные он будет получать из брокера очередей, но для этого их туда еще положить надо. В общем так же выглядит оверхедом.

Возникает вопрос: может быть брокеры очередей в принципе не подходят для подобного типа задач и созданы для другого? Или я как-то не правильно его готовлю?
  • Вопрос задан
  • 5485 просмотров
Пригласить эксперта
Ответы на вопрос 5
Очередь это буфер, куда задачи попадают с разной скоростью, а из него сливаются равномерно, по мере готовности «рабочих» их принять.

В вопросе описана так-себе реализация с поллингом очереди. Различие без-очереди и с-очередью — в направлении инициативы:
  • без очередей «рабочий» опрашивает базу снова и снова: «есть чё?». Это как из браузера ajax'ом пинговать сервер раз в секунду в поиске сообщений. Работает, но такое себе..
  • с очередью инициатор процесса – брокер. Это брокер передаёт очередную задачу на исполнение первому освободившемуся «рабочему».

spoiler
Про потерю данных при падении — че-т страшилка, далёкая от продакшена. Драйвером очереди может быть и Redis (со своей персистентностью) и MySQL какой-нибудь, и другие. Имхо костыльно пихать в очередь всего лишь id записи в БД, которую надо обработать – чтобы рабочий, взявший задачу, заново собирал данные. Это не кошерно и калорийно.

Лучше класть в очередь самодостаточную задачу. Например, сериализовать модель. Чтобы рабочий, получивший задачу, уже не обращался к базе – а только наполнял темплейт письма данными из полученной модели и отправлял послание. И в БД проставлял статус «отправлено»
Ответ написан
Комментировать
zoonman
@zoonman
⋆⋆⋆⋆⋆
В первую очередь брокеры нужны для балансировки нагрузки и увеличения надежности и скорости работы системы в целом.

В вашем приведенном примере приведен способ уведомления клиента о каком-то событии. Например о том, что его заказ обработан, отправлен, доставлен и т.д. Событий может быть много и их источники могут быть различными.
Например у вас может быть интеграция со сторонней системой логистики. А еще с 10 разными системами оплаты.
Еще есть маркетинг, который тоже хочет отправлять массовые рассылки.
Получается, что под каждый случай вам прийдется хранить информацию о письмах и статусах. Но даже проблема не в этом, проблема в том, что каждое событие имеет разный приоритет и разную ценность.

В случае работы с сайтом у вас будет 1 воркер, который будет просто сканировать таблицы на поиск неуведомленных пользователей. Если у вас будет 2 воркера, надо делать систему блокировок и т.д. Т.е. мы упираемся в проблему масштабирования. Для решения задачи разной скорости уведомлений, вы построите систему приоритетов или будете делать разные таблицы с разными воркерами. Это все будет работать, но нагрузка на базу будет серьезной и она будет увеличиваться с ростом пользовательской базы. Опять вы упретесь в тормоза.
Опять же есть письма, которые должны быть доставлены немедленно, вроде подтверждений аккаунта, смены пароля и т.д. Еще одна таблица? Дополнительный приоритет? Может так произойти, что вы некоторые пользователи вообще никогда не получат писем и уведомлений. Прийдется придумывать способ контроля.
Я уж не говорю о куче кастомных воркеров под каждую ситуацию. И их будет с десяток, не меньше.

Очереди решают, т.к. можно сделать их несколько и на для каждой настроить определенное количество абсолютно одинаковых воркеров. Пример с поллингом отвратителен и сейчас никто так не делает, а с очередями делают так.
У вас может быть цепочка из нескольких воркеров, когда результат работы одного помещается в очередь.
Например, когда надо сначала достать данные из нескольких разных медленных систем, отрендерить в шаблон, а потом отправить письмо. Сборка, рендеринг и отправка - три разные компонента, последние два из которых, можно активно переиспользовать для других целей изменяя лишь конфигурацию времени исполнения.
При таком подходе проще развивать кодовую базу, исправлять ошибки, т.к. они изолированы в одном месте, а не разбросаны по всей системе. И да, косяк в "горячем" модуле вы заметите немедленно. А самое прикольное то, что ваш косяк, пользователи и не заметят, для них это будет выглядеть как простая задержка, а у вас будет время на то, чтобы исправить ошибку. Сообщения посидят в очереди и все.
Но это еще не все, ваши воркеры могут быть написаны на разных языках программирования. Например пользователь может загружать фото на сайт на PHP, объекты распознаваться на Python, видео рендериться на Rust, а отправка писем может быть на Go. И такой подход может подойти для сложных систем с распределенными командами и различным уровнем компетенция в применяемых технологиях. Специалистов превосходно владеющих всеми приведенными технологиями просто единицы, и поверьте, они решают задачи совершенно другого уровня.
Ответ написан
Комментировать
glaphire
@glaphire
PHP developer
Для простого приложения, как в описании вопроса, это действительно оверхед)
По ответам из разных источников получается, что реббит становится полезен тогда, когда в системе появляется много продюсеров и консюмеров, и реббит, как самостоятельная прослойка, инкапсулирует логику рассылки, попыток переотправки и т.д. То, что сообщеня могут теряться это да, проблема, но можно снизить ее вероятность, если углубиться в настройки и покрутить экстеншены реббита
Ответ написан
@qbudha
Чых-пыхдевелопер

... Хендлер так же каждые 5 секунд опрашивает, но уже не базу, а брокер очередей, на предмет появления новых тасков. Выполняет таск и ставит в базе данных статус "done".


Из преимуществ - первому хендлеру не нужно подключение к базе, все данные он будет получать из брокера очередей, но для этого их туда еще положить надо


В принципе Вы сами описали преимущества — разгрести очередь быстрее, чем сходить в БД. Профит будет тогда, когда появится нагрузка.
Ну и опять же, всё зависит от ЯП, например, на PHP скидывать сообщение в очередь это более-менее устоявшееся production level решение проблемы отсутствия асинхронности и корутин.
А если Ваш ЯП поддерживает асинхронные вызовы и может не блокировать основной поток выполнения, то может быть Вам пока и не нужны очереди.
Еще в очереди скидывают большие задачи, которые точно займут много времени — это всякий рендеринг видео и тому подобные расчёты.

Upd
Корутины в PHP, конечно же есть. Но я их не юзал и сказать про них ничего не могу:(
Ответ написан
Комментировать
saboteur_kiev
@saboteur_kiev
software engineer
а брокеры очередей в случае падения теряют данные.

Это неверно.
Брокеры бывают разные и настроены по разному.
В общем случае, брокер - вещь гораздо более легковесная, чем база данных. Гораздо проще масштабируется и кластеризируется, чем база данных. Да и работает в основном гораздо быстрее.

Но в вашем случае - отправлять уведомление пользователю, это не совсем задача для брокеров. Брокеры в основном нужны для общения микросервисов/программ друг с другом.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы