dasha_programmist
@dasha_programmist
ex Software Engineer at Reddit TS/React/GraphQL/Go

Как правильно организовать очереди?

Есть некое приложение:
- несколько реплик микросервисов (сервис_1), которые держат WebSocket соединение с клиентом (либа centrifuge)
- брокер rabbitmq
- stateless сервис бизнес логики (сервис_2) для общения с базой
- redis для хранения сквозных данных между репликами сервисов

Юз кейс такой:
1) клиент коннектится на любой инстанс сервиса_1, шлет команду
2) команда сервисом_1 отсылается в брокер
3) сервис_2 читает команду, зная кто и что запрашивает
4) сервис_2 отправляет в брокер команду, которая должна быть направлена в нужный инстанс и далее нужному клиенту

Вопрос: как правильно организовать отправку команды сервис_2 -> сервис_1 ? Проблема в том как узнать какой сервис на каких пользователей подписан? хранить эту связь в redis? Или на каждого пользователя создавать по очереди? Или это все одна очередь и каждое сообщение должно быть вычитано каждым инстансом сервиса_1 а затем отфильтровано?
  • Вопрос задан
  • 673 просмотра
Пригласить эксперта
Ответы на вопрос 3
ayazer
@ayazer
Sr. Software Engineer
я конечно мимокрокодил с другого стека, но как вариант:

запрос идет на какую-то проксю, откуда по по sha1 от идентификатора сессии перекидывает на нужный сервер. т.к эта логика будет отрабатывать только на момент хендшейка - она не станет боттлнеком. а если будет упиратся в потолок то вертикальное маштабирование тут будет стоить копейки (в сравнении с ценой всей остальной инфраструктуры). Если пинг важен - можно еще L4 (спереди) и раскидывать на разные регионы.

в этот момент мы уже получаем равномерное распределение пользователей по серверам И возможность гарантировано по идшнику понять на каком с серверов висит коннекшн. самая очевидная проблема - автоматический скейлинг этого всего в обе стороны. бо прийдется много жонглировать. условиях не идеального коннекта/загруженой сетке тут будут обрывы (но возможно это и допустимый компромисс).

как узнать какой сервис на каких пользователей подписан

по идентификатору мы сразу понимаем на какой конкретно инстанс идти. если обрыв коннекшена - сходить куда-то в окестратор уточнить куда теперь слать данные.

хранить эту связь в redis
можно и в редис. по сути прийдется хранить только маски какой диапазон на какой сервер идут. и при скейлинге - обновлять.

Или на каждого пользователя создавать по очереди? Или это все одна очередь и каждое сообщение должно быть вычитано каждым инстансом сервиса_1 а затем отфильтровано?

если честно выглядит как оверхед, не вижу проблемы чтоб все пихать в 1 очередь, с которой воркеры будут разгребать работу. только перепроверьте что ваша очередь действительно гарантирует что сообщение прочитают именно 1 раз, у того-же амазоновского скса формулировка про "точно 1 раз".
Ответ написан
Комментировать
@yarkin
Если клиент не закрывает соединение с конкретным инстансом (или если закрыл, то ответ не должен получить), то посмотрите в сторону RPC, вот с помощью чего оно работает, вот примеры.
Если результат требует много вычислительных ресурсов и повторять нежелательно, то либо создавать очереди под каждого клиента, либо где-то кэшировать результат (например, в СУБД).
Ответ написан
А в чём проблема отправлять из сервис_1 в брокер и идентификатор пользователя и идентификатор сервиса (экземпляра), к которому он подключен? Тогда каждый экземпляр сервис_2 будет знать кому предназначена команда. Не вижу смысла плодить очереди на каждого пользователя (и тем более заниматься их управлением) и даже для каждого экземпляра сервис_1.
Так что я за более простой вариант:
Или это все одна очередь и каждое сообщение должно быть вычитано каждым инстансом сервиса_1 а затем отфильтровано?
Ответ написан
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы