Распространение сервера приложений

У меня есть сервер приложений. На высоком уровне этот сервер приложений имеет пользователей и группы. Пользователи являются частью одной или нескольких групп, и сервер информирует всех пользователей о состоянии их групп и других пользователей в их группах. Есть три основные функции:

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

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

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

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

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

Однако это только сводит к минимуму частоту общения пользователей на разных серверах. У меня все еще есть проблема с общением между пользователями на разных серверах.

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

Например, если я подключен к серверу A и мне нужен прокси-сервер с другим пользователем, подключенным к серверу B, я бы попросил сервер A для прокси-подключения к этому пользователю. Сервер А увидит, что другой пользователь подключен к Серверу Б, поэтому установит "релейное" соединение с Сервером Б. Это соединение будет просто пересылать мои запросы на сервер B, а ответы — мне.

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

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


person Collin Dauphinee    schedule 12.04.2011    source источник
comment
На какой ОС и на каком языке написан сервер?   -  person Jim Morris    schedule 12.04.2011
comment
Это чрезвычайно сложная тема. В прошлый раз, когда я писал что-то подобное на C++, синхронизация серверов была очень сложной и подвергалась очень неприятным условиям гонки. Недавно я написал что-то очень похожее на Erlang, и это было относительно легко.   -  person Jim Morris    schedule 12.04.2011
comment
Проблема сейчас не в сложности решения, а в поиске «наилучшего» возможного решения.   -  person Collin Dauphinee    schedule 12.04.2011


Ответы (1)


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

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

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

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

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

Сопровождение серверного кода было кошмаром, и это действительно не самый эффективный способ реализации масштабируемых серверов. Но если вам нужно использовать кодовую базу устаревшего сервера, у вас действительно не так много вариантов.

Если вы можете изучить язык, который поддерживает удаленные процессы и узлы, такие как Erlang.

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

person Jim Morris    schedule 12.04.2011
comment
Спасибо за предложение. Я забыл упомянуть, что серверы не будут находиться в одной локальной сети; одним из самых больших узких мест на данный момент является пропускная способность. И нет, сервер состоит из 150 000+ строк C++, поэтому изменения должны быть сведены к минимуму. - person Collin Dauphinee; 12.04.2011
comment
Если бы мне пришлось сделать это снова (у меня была аналогичная ситуация с вами, задним числом сделав автономный сервер распределенным), я бы обязательно изучил маршрут очереди сообщений (RabbitMQ). Таким образом, все серверы должны подключаться к очереди сообщений и отслеживать определенные каналы. Затем они отвечают обратно, используя очередь сообщений. Это не поможет вам решить проблему с пропускной способностью. но это сделает передачу сообщения намного проще. - person Jim Morris; 12.04.2011
comment
К вашему сведению, несколько лет спустя я переписал совместимый распределенный сервер на Erlang, это заняло намного меньше времени, чем исходный сервер, и было намного чище и проще. Также код был в десять раз меньше строк кода. У меня было гораздо меньше условий для гонок, а раздача встроена... Просто говорю :) - person Jim Morris; 12.04.2011