Привет всем, мне нужно создать службу, которая могла бы получать сообщения из потока данных FIFO и отправлять сообщения по порядку на каждый клиентский сервер.
Допустим, поток данных содержит A1, A2, A3, A4, B1, B2, B3, C1, C2 и т. д., тогда мне нужно отправить сообщение A1, A2, A3, A4 последовательно на сервер A, сообщение B1, B2, B3, B4 последовательно на сервер B и так далее. Каждый клиентский сервер должен получать сообщения по порядку. Поток входных данных гарантированно будет в порядке.
Требования:
Вот проблема, с которой я столкнулся:
Существует высокая вероятность того, что клиентские серверы не отвечают. В этом случае службе необходимо подождать и прекратить отправку сообщений на этот клиентский сервер до тех пор, пока клиентский сервер не будет готов принимать сообщения. (например, сервер A не работает, тогда служба должна прекратить отправку сообщений на сервер A, но служба продолжает отправлять сообщения на другие не отключенные серверы).
Вот мое текущее решение:
Я думал о сохранении всех сообщений из потока входных данных в БД. В то же время существует задание cron, которое выберет первое сообщение из БД, где сообщение не отправлено, в порядке их отметки времени. Выбранные сообщения будут отправлены асинхронно на соответствующий клиентский сервер.
Однако я читаю много блогов в Интернете, и они не предлагают хранить сообщения в БД (Никогда не используйте базу данных в качестве очереди сообщений), поэтому я ищу другие предложения по архитектуре, но не смог их найти.
Есть ли у вас какие-нибудь предложения по архитектуре для этого?
Разрешены любые сторонние сервисы (AWS, GCP, Kafka, Ably и т. д.).
Учитывая упомянутые вами ограничения доступности сервера, я бы подумал о решении, использующем одну очередь на сервер.
По сути, ваше приложение считывает из очереди FIFO, накапливает в памяти 10 сообщений на каждый сервер (например, для сервера A) и помещает эти сообщения в выделенную очередь, которая используется только сервером A.
Таким образом, вы переключаете модель передачи данных с push-на основе на pull-ориентированную и вам не нужно беспокоиться о доступности сервера A, потому что, если он выйдет из строя, сообщения останутся в его очереди, а когда он снова включится, он будет отключен. обрабатывать последние сообщения в том же порядке.
Конечно, вам понадобится более 1 миллиона очередей. Если вы используете AWS SQS, который гарантирует упорядочивание логики доставки FIFO, ограничений на количество очередей, которые вы можете создать для каждой учетной записи, нет, поэтому, по крайней мере, технически это должно работать.
Для таких случаев использования с высокой пропускной способностью и низкой задержкой я бы не стал использовать БД (особенно реляционную), потому что она может быстро стать узким местом.
Вместо этого я бы проверил Redis Streams , чтобы узнать, подходит ли он для этого варианта использования. Некоторые говорят, что он довольно хорошо справляется с 200 тысячами потоков, я думаю, что без проблем можно увеличить до 1 миллиона+.
Насколько я знаю, Redis не подходит для долгосрочного хранения сообщений. В моем случае возможно, что клиентский сервер не работает годами. Комбинация базы данных Redis и NoSQL (возможно, Cassandra) может работать. Что вы думаете?
Я использовал Cassandra в производстве в течение многих лет и могу сказать, что с ней нелегко играть. Конечно, это может сработать, но это всегда компромисс между временем и затратами.
Вариант использования, с которым вы столкнулись, довольно ясен и является типичным для решений для обмена сообщениями. Поскольку у вас есть один потребитель на, скажем, группу сообщений, вы можете использовать либо очереди сообщений (более подходящие), либо pub/sub. Особенно тот факт, что клиент может какое-то время не отвечать, приводит к такому типу общения для повышения производительности.
Что касается технологий, вы можете выбирать из множества доступных (тем более, что у вас нет каких-либо требований к размеру/типу сообщения). Например, kafka может обрабатывать указанные вами числа, порядок можно выполнить довольно легко, он также сохраняет сообщения, если хотите, есть много поддержки в Интернете, он масштабируем и бесплатен.
Аналогично с RabbitMQ и ActiveMQ. Я не использовал их в больших объемах, но теоретически они оба могут удовлетворить ваши требования, они масштабируемы и бесплатны.
Если вы используете облачные сервисы, есть готовые полностью управляемые варианты, такие как AWS SQS, как уже упоминалось, GoogleCloud pub/sub и т. д. Так что их проще использовать, но они не бесплатны!
Если вы все еще не хотите пробовать какую-то новую технологию, даже если она лучше всего подходит для вашего случая, я бы предложил избавиться от cronJob и заставить клиентов отправлять запросы к БД. Потому что, если клиенты 1M не отвечают в течение минуты, cronJob все равно выполняет запросы к БД и клиентам 1M, и это звучит избыточно. Вы можете использовать Redis для сопоставления сервера с записями из БД и даже не беспокоить основную БД, если для этого клиента нет сообщений. Конечно, вам следует рассмотреть возможность использования лучших практик повышения производительности запросов, которые хорошо подходят в вашем случае, таких как индексирование и секционирование.
Возможно, вы сможете почерпнуть некоторые идеи, основываясь на том, как Slack обрабатывает большие объемы сообщений: Обмен сообщениями в реальном времени — Slack Engineering