связь через веб-сокет между клиентами в распределенной системе

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

Основная идея состоит в том, чтобы получить сообщение от client1 и уведомить об этом client2. Но вот в чем дело. Мое приложение будет работать на GAE. А что, если сокет client1 открыт на server1, а client2 открыт на < em>сервер2. Эти серверы не знают о клиентах друг друга.

У меня есть одна идея, как это решить, но я уверен, что это дерьмовый способ. Я собираюсь использовать какую-то связь между серверами (например, JMS или открыть другое соединение через веб-сокет между серверами, сейчас это не имеет значения).
Но это наверняка приведет к катастрофе. Я даже не могу представить, как часто эти серверы будут разговаривать друг с другом. Для каждого сообщения сервер1 должен уведомлять сервер2, сервер2 > должен уведомить client2. Но все становится еще хуже, когда в игру вступает серверN.

Еще один способ, которым я вижу это, — это Firebase. Но он ограничивает размер сообщения до 4 КБ. Поэтому я не могу отправлять аудио через него. В качестве решения я могу уведомить клиента о новом звуке, и он отправится за ним на мой сервер.

Надеюсь, я ясно объяснил проблему. Кто-нибудь знает, как это решить? Или, может быть, есть другие способы создания таких приложений?


person Vladislav Gutov    schedule 12.07.2016    source источник
comment
вопрос несколько широк. каждая часть имеет свое решение. например, для аудио отправьте идентификатор сохраненного аудио, а не сами аудиоданные.   -  person Zig Mandel    schedule 13.07.2016
comment
Да, я думал сделать это так, но все же. Основная проблема заключается в том, чтобы каким-то образом уведомить другой сервер о сообщении client1 для client2.   -  person Vladislav Gutov    schedule 14.07.2016
comment
извините, мой комментарий был обрезан. Это не проблема, если ваш сервлет не имеет состояния. Храните все в хранилище данных (с кэшированием), и сообщение содержит все необходимые данные для его идентификации в хранилище данных. Также рассмотрите firebase.   -  person Zig Mandel    schedule 14.07.2016
comment
По сути, вы предлагаете мне сохранить сообщение в базе данных (или в кеше), а затем получить его на другой стороне? Если да, не будет ли это слишком тяжело для сервера и базы данных? Допустим, каждый клиент опрашивает базу данных каждую секунду. Они будут перегружать базу данных. Или я ошибаюсь? Мой друг обнаружил, что у akka есть решение для общения актеров в распределенной системе. Это позволяет искать их по имени, как если бы они были созданы на одной машине. Я еще не проверял эту информацию, но надеюсь, что да. Может быть, я должен использовать их тогда.   -  person Vladislav Gutov    schedule 14.07.2016


Ответы (2)


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

  • Во-первых, если вы не используете балансировку нагрузки, ваши клиенты будут подключаться к одному и тому же серверу в среднем 50% времени (в случае 2 серверов).
  • Во-вторых, каналы внутри центра обработки данных являются быстрыми и бесплатными во всех известных общедоступных облаках.
  • В-третьих, вы часто можете сделать что-то умное на внешнем интерфейсе, чтобы убедиться, что два клиента, которые могут обмениваться данными, подключаются к одному и тому же серверу. Например, направьте всех клиентов из одной страны на один и тот же сервер, используя балансировку нагрузки DNS.

Вторая часть вопроса касается передачи больших медиафайлов. Обычно рекомендуется отправлять его вне диапазона - хранить на сервере и передавать только ссылку на него. Как кто-то предложил в комментарии, сохраните аудио на сервере и просто отправьте сообщение типа «аудио доступно, возьмите его отсюда ...». Вам не нужно опрашивать сервер для этого. Просто извлеките его один раз, когда клиент-получатель запрашивает его.

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

person Gene S    schedule 08.08.2016

  1. Пусть все клиенты подключаются к нескольким серверам, и каждый сервер сохраняет эти метаданные.
  2. Централизованная система, такая как zookeeper, хранит информацию об активных серверах.
  3. Когда клиент c1 отправляет сообщение клиенту c2:

    • the message is received by a server (say s1, we can add lad balancer to distribute incoming requests)
    • s1 будет транслировать эту информацию на все остальные серверы, чтобы узнать, к какому серверу подключен клиент c2 ИЛИ лучше использовать последовательное хеширование, которое решает, к какому серверу клиент может подключиться, и в этом подходе широковещательное сообщение не требуют
    • соответствующие ответы сервера серверу s1 (скажем, s2)
    • теперь s1 отправляет сообщение m на s2 и сервер s2 клиенту c2

Минусы описанного выше подхода:

  1. Каждый сервер будет иметь соединение с n-1 серверами, создавая ячеистую топологию.

  2. Централизованная система (zookeeper) становится единой точкой отказа (что решаемо)

Такие приложения, как Whatsapp, G-Talk, используют XMPP и TCP/IP.

person Bishnu    schedule 08.02.2020