Горизонтальное масштабирование и GraphQL в среде Node.js

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

В статья я читал, что можно создавать приложения в реальном времени с использованием GraphQL с «подписками», и в дополнение к этому, это простой в использовании протокол, а его преимущество сводится к минимуму извлечения объектов в оба конца и, следовательно, к меньшему использованию ресурсов.

Но что, если нам нужно добавить в систему новый сервер / узел для горизонтального масштабирования? Возможно ли это с помощью GraphQL?

В качестве примера реализации веб-сокетов, допускающих горизонтальное масштабирование, есть SocketCluster. Интересно, может ли приложение, разработанное только с помощью GraphQL, масштабироваться на нескольких узлах / машинах, или оно должно использоваться с другой структурой, такой как SocketCluster, для достижения этой цели.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
1 060
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вкратце - да. Мы сделали это, и он работает очень хорошо.

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

Для этого мы использовали системы массового обслуживания, а именно RabbitMQ.

Представьте себе такой сценарий создания отчета, который может занять до 10 минут:

  1. Клиент подключается к нашему GraphQL API (экземпляр 1) через WebSocket
  2. Клиент отправляет команду на создание отчета через WebSocket
  3. API генерирует токен для команды и помещает команду для создания отчета в CommandQueue (в RabbitMQ), возвращая токен клиенту.
  4. Клиент подписывается на события результата своей команды, используя токен
  5. Какой-то backend Worker подхватывает команду и выполняет процедуру генерации отчета
  6. За это время умирает GraphQL API (экземпляр 1)
  7. Клиент автоматически переподключается к GraphQL API (экземпляр 2)
  8. Клиент продлевает подписку с помощью ранее приобретенного токена
  9. Рабочий готов, результаты в EventsQueue (RabbitMQ)
  10. ВСЕ наши экземпляры GraphQL получают информацию о ReportGenerationDoneEvent и проверяют, прослушивает ли кто-нибудь его токен.
  11. GraphQL API (экземпляр 2) видит, что Клиент ожидает результатов. Отправляет результаты через веб-сокеты.
  12. GraphQL API (экземпляры 3-100) игнорирует ReportGenerationDoneEvent.

Он довольно обширен, но с простыми абстракциями вам не нужно думать обо всей этой сложности и писать ~ 30 строк кода для нескольких служб для нового процесса, использующего этот маршрут.

И что в этом замечательного, вы получаете хорошее горизонтальное масштабирование, возможность повторного воспроизведения событий (повторные попытки), разделение проблем (клиент, api, рабочие), как можно быстрее отправляете данные клиенту, и, как вы упомянули, вы делаете не тратить пропускную способность на запросы are we done yet?.

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

Хорошие мысли о SocketCluster. Это позволит оптимизировать шаг 10 в приведенном выше сценарии, но на данный момент мы не видим никаких проблем с производительностью при широковещательной передаче ReportGenerationDoneEvent на весь кластер API. При большем количестве экземпляров или многорегиональной архитектуре это было бы необходимо, поскольку это позволило бы улучшить масштабирование и сегментирование.

Важно понимать, что SocketCluster работает на уровне взаимодействия (WebSockets), но уровень логического API (GraphQL) находится над ним. Чтобы оформить подписку GraphQL, вам просто нужно использовать протокол связи, который позволяет передавать информацию пользователю, а WebSockets позволяет это.

Я думаю, что использование SocketCluster - хороший выбор для дизайна, но не забудьте повторить итерацию с реализацией. Используйте SocketCluster только тогда, когда вы планируете открыть много сокетов в любой момент времени. Кроме того, вы должны подписываться только при необходимости, потому что WebSocket отслеживает состояние и требует управления и пульса.

Если вас также интересует асинхронная серверная архитектура, которую я использовал выше, прочитайте о шаблонах CQRS и Event Sourcing.

Спасибо за ваш ответ. Просто чтобы хорошо понять: когда вы говорите об использовании GraphQL API через Websocket, вы имеете в виду, что вы инициируете соединение с сокетом через Websocket, а затем обрабатываете обмен данными с GraphQL? Я все еще новичок в этих технологиях, поэтому, пожалуйста, поправьте меня, если я ошибаюсь: не эквивалентны ли подписки GraphQL и соединения WebSocket? В чем преимущество использования GraphQL с SocketCluster, если не для масштабирования и сегментирования?

Strider 03.05.2018 03:53

Когда вы настраиваете свой проект для использования WebSockets, вы теоретически можете отказаться от всех HTTP-запросов GraphQL и просто использовать WebSockets для связи. Чтобы оформить подписку GraphQL, вам просто нужно использовать протокол связи, который позволяет передавать информацию пользователю, а WebSockets позволяет это. Таким образом, они не эквивалентны, они работают на разных уровнях - подписка GQL находится на логическом уровне более высокого уровня и использует WebSocket для передачи данных. Кроме того, использование SocketCluster в основном даст вам то, что вы только что сказали - масштабирование и сегментирование.

Marcin Natanek 03.05.2018 12:45

В комбинированном дизайне REST и Websockets (см. Вопрос stackoverflow.com/a/43971625/5486116) многие рекомендуют реализовать решение, в котором мы подписываемся на изменения только в случае необходимости. Я думаю, что это решение потребляет меньше ресурсов и дает лучшую производительность ... что, если мы хотим применить ту же логику при объединении веб-сокетов с GraphQL: мы общаемся в основном через Websocket (SocketCluster), и для любого обмена данными мы используем GraphQL, и Конечно, SocketCluster будет в основном отвечать за масштабируемость и сегментирование. Это хороший дизайн?

Strider 03.05.2018 17:21

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

Marcin Natanek 03.05.2018 17:53

Еще раз спасибо за ваше руководство. Что вы думаете о добавлении резюме к вашему ответу, чтобы больше людей могли извлечь пользу из того, что вы мне рассказали в своих комментариях?

Strider 03.05.2018 18:21

Другие вопросы по теме