Упорядоченная архитектура службы обмена сообщениями

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

Допустим, поток данных содержит A1, A2, A3, A4, B1, B2, B3, C1, C2 и т. д., тогда мне нужно отправить сообщение A1, A2, A3, A4 последовательно на сервер A, сообщение B1, B2, B3, B4 последовательно на сервер B и так далее. Каждый клиентский сервер должен получать сообщения по порядку. Поток входных данных гарантированно будет в порядке.

Требования:

  1. Количество сообщений, попадающих в поток данных, составляет до 10 000 сообщений в секунду.
  2. Количество различных клиентских серверов достигает 1 000 000 и увеличивается. (А, Б, В, ...)
  3. Количество последовательностей сообщений на клиентские серверы — до 10 последовательных сообщений. (А1, А2, ..., А10)
  4. Клиентские серверы должны получать сообщения практически в режиме реального времени (менее чем через 2 минуты после того, как сообщения попадают в поток данных).

Вот проблема, с которой я столкнулся:

Существует высокая вероятность того, что клиентские серверы не отвечают. В этом случае службе необходимо подождать и прекратить отправку сообщений на этот клиентский сервер до тех пор, пока клиентский сервер не будет готов принимать сообщения. (например, сервер A не работает, тогда служба должна прекратить отправку сообщений на сервер A, но служба продолжает отправлять сообщения на другие не отключенные серверы).

Вот мое текущее решение:

Я думал о сохранении всех сообщений из потока входных данных в БД. В то же время существует задание cron, которое выберет первое сообщение из БД, где сообщение не отправлено, в порядке их отметки времени. Выбранные сообщения будут отправлены асинхронно на соответствующий клиентский сервер.

Однако я читаю много блогов в Интернете, и они не предлагают хранить сообщения в БД (Никогда не используйте базу данных в качестве очереди сообщений), поэтому я ищу другие предложения по архитектуре, но не смог их найти.

Есть ли у вас какие-нибудь предложения по архитектуре для этого?

Разрешены любые сторонние сервисы (AWS, GCP, Kafka, Ably и т. д.).

Возможно, вы сможете почерпнуть некоторые идеи, основываясь на том, как Slack обрабатывает большие объемы сообщений: Обмен сообщениями в реальном времени — Slack Engineering

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

Ответы 2

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

Учитывая упомянутые вами ограничения доступности сервера, я бы подумал о решении, использующем одну очередь на сервер.

По сути, ваше приложение считывает из очереди FIFO, накапливает в памяти 10 сообщений на каждый сервер (например, для сервера A) и помещает эти сообщения в выделенную очередь, которая используется только сервером A.

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

Конечно, вам понадобится более 1 миллиона очередей. Если вы используете AWS SQS, который гарантирует упорядочивание логики доставки FIFO, ограничений на количество очередей, которые вы можете создать для каждой учетной записи, нет, поэтому, по крайней мере, технически это должно работать.

Для таких случаев использования с высокой пропускной способностью и низкой задержкой я бы не стал использовать БД (особенно реляционную), потому что она может быстро стать узким местом.

Вместо этого я бы проверил Redis Streams , чтобы узнать, подходит ли он для этого варианта использования. Некоторые говорят, что он довольно хорошо справляется с 200 тысячами потоков, я думаю, что без проблем можно увеличить до 1 миллиона+.

Насколько я знаю, Redis не подходит для долгосрочного хранения сообщений. В моем случае возможно, что клиентский сервер не работает годами. Комбинация базы данных Redis и NoSQL (возможно, Cassandra) может работать. Что вы думаете?

Justin Xu 03.05.2024 06:44

Я использовал Cassandra в производстве в течение многих лет и могу сказать, что с ней нелегко играть. Конечно, это может сработать, но это всегда компромисс между временем и затратами.

Cosmin Ioniță 03.05.2024 19:38

Вариант использования, с которым вы столкнулись, довольно ясен и является типичным для решений для обмена сообщениями. Поскольку у вас есть один потребитель на, скажем, группу сообщений, вы можете использовать либо очереди сообщений (более подходящие), либо pub/sub. Особенно тот факт, что клиент может какое-то время не отвечать, приводит к такому типу общения для повышения производительности.

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

Аналогично с RabbitMQ и ActiveMQ. Я не использовал их в больших объемах, но теоретически они оба могут удовлетворить ваши требования, они масштабируемы и бесплатны.

Если вы используете облачные сервисы, есть готовые полностью управляемые варианты, такие как AWS SQS, как уже упоминалось, GoogleCloud pub/sub и т. д. Так что их проще использовать, но они не бесплатны!

Если вы все еще не хотите пробовать какую-то новую технологию, даже если она лучше всего подходит для вашего случая, я бы предложил избавиться от cronJob и заставить клиентов отправлять запросы к БД. Потому что, если клиенты 1M не отвечают в течение минуты, cronJob все равно выполняет запросы к БД и клиентам 1M, и это звучит избыточно. Вы можете использовать Redis для сопоставления сервера с записями из БД и даже не беспокоить основную БД, если для этого клиента нет сообщений. Конечно, вам следует рассмотреть возможность использования лучших практик повышения производительности запросов, которые хорошо подходят в вашем случае, таких как индексирование и секционирование.

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