#c #windows #distributed #application-server #distributed-system
#c #Windows #распределенный #сервер приложений #распределенная система
Вопрос:
У меня есть сервер приложений. На высоком уровне этот сервер приложений имеет пользователей и группы. Пользователи являются частью одной или нескольких групп, и сервер информирует всех пользователей о состоянии их групп и других пользователей в их группах. Существует три основные функции:
- Обновление и трансляция метаданных, относящихся к пользователям и их группам; например, пользователь входит в систему, и сервер обновляет статус этого пользователя и транслирует его всем онлайн-пользователям в группах этого пользователя.
- Действует как прокси между двумя или более пользователями; клиент использует преимущества одноранговой передачи, но в случае, если два пользователя не могут напрямую подключиться друг к другу, сервер будет действовать как прокси между ними.
- Хранение данных для автономных пользователей; если клиенту необходимо отправить некоторые данные пользователю, который не подключен к сети, сервер сохранит эти данные в течение определенного периода времени, а затем отправит их, когда пользователь в следующий раз подключится к сети.
Я пытаюсь модифицировать это приложение, чтобы оно могло распространяться по нескольким серверам, не обязательно все в одной локальной сети. Однако у меня есть требование, чтобы обратная совместимость со старыми клиентами не нарушалась; по сути, распространение должно быть прозрачным для клиента.
Самая большая проблема, с которой я сталкиваюсь, заключается в обработке случая, когда пользователь, подключенный к серверу A, вносит обновление, которое должно быть передано пользователю на сервере B.
Более того, еще большая проблема возникает, когда пользователю на сервере A требуется, чтобы сервер действовал как прокси-сервер между ними и пользователем на сервере B.
Моей первоначальной идеей было попытаться назначить каждому пользователю предпочитаемый сервер, используя некоторый алгоритм, который учитывает, с какими пользователями им необходимо взаимодействовать. Это может уменьшить количество пользователей, которым может потребоваться взаимодействовать с пользователями на других серверах.
Однако это лишь сводит к минимуму частоту взаимодействия пользователей на разных серверах. У меня все еще есть проблема с обеспечением связи между пользователями на разных серверах.
Единственное решение, которое я смог придумать для этого, — это подключение серверов друг к другу, когда им нужно иметь дело с пользователем, подключенным к другому серверу.
Например, если я подключен к серверу A и мне нужен прокси-сервер с другим пользователем, подключенным к серверу B, я бы попросил сервер A установить прокси-соединение с этим пользователем. Сервер A увидит, что другой пользователь подключен к серверу B, поэтому установит «ретрансляционное» соединение с сервером B. Это соединение просто переадресует мои запросы на сервер B, а ответы — мне.
Проблема в том, что это увеличило бы использование полосы пропускания, которая и так чрезвычайно высока. К сожалению, я не вижу никакого другого решения.
Существуют ли какие-либо хорошо известные или лучшие решения этой проблемы? Не похоже, что для распределенной системы часто требуется обмен данными между пользователями на разных серверах.
Комментарии:
1. На каких O / S и языке написан сервер?
2. Это чрезвычайно сложная тема. В прошлый раз, когда я писал что-то подобное на C , синхронизация серверов была действительно сложной и зависела от действительно неприятных условий гонки. Недавно я написал нечто очень похожее на Erlang, и это было относительно просто.
3. Проблема прямо сейчас на самом деле заключается не в сложности решения, а в поиске «наилучшего» возможного решения.
Ответ №1:
Я не знаю, насколько гибко вы можете модифицировать существующий сервер. Способ, которым я сделал это давным-давно, заключался в том, чтобы все серверы поддерживали TCP-соединение открытым друг для друга. Я использовал широковещательную передачу UDP, которая сообщала другим серверам друг о друге и позволяла им подключаться к новым серверам и удалять серверы, которые прекратили отправку широковещательной передачи.
Затем каждый раз, когда пользователь подключается к серверу, этот сервер одноадресно отправляет TCP-сообщение на все серверы, к которым он подключен, и все серверы сохраняют список пользователей и на каком сервере они находятся.
Затем, как вы предлагаете, если вы получаете сообщение от одного пользователя другому пользователю на другом сервере, вы должны передать его на другой сервер. Серверы действительно должны находиться в одной локальной сети, чтобы это работало хорошо.
Вы можете запускать обмен данными между серверами в потоке и фактически имитировать пользователя, находящегося на том же сервере.
Однако ведение списков пользователей и отправка сообщений подвержены условиям гонки (например, пользователь отключается, пока вы передаете сообщение с одного сервера на другой и т.д.).
Поддержание серверного кода было кошмаром, и это действительно не самый эффективный способ реализации масштабируемых серверов. Но если вам приходится использовать устаревшую серверную кодовую базу, то у вас действительно не так уж много вариантов.
Если вы можете рассмотреть возможность использования языка, который поддерживает удаленные процессы и узлы, такие как Erlang.
Альтернативой может быть использование системы очередей сообщений, такой как RabbitMQ или ActiveMQ, и заставить серверы взаимодействовать друг с другом через это. Эти системы спроектированы так, чтобы быть масштабируемыми, и обычно работают с механизмом публикации / подписки.
Комментарии:
1. Спасибо за предложение. Я забыл упомянуть, что серверы не будут находиться в одной локальной сети; одним из самых больших узких мест на данный момент является пропускная способность. И нет, сервер состоит из более чем 150 000 строк C , поэтому изменения должны быть сведены к минимуму.
2. Если бы я должен был сделать это снова (у меня была похожая ситуация с вами, когда я ретроактивно распределял автономный сервер), я бы, конечно, изучил маршрут очереди сообщений (RabbitMQ). Таким образом, все серверы должны подключаться к очереди сообщений и отслеживать определенные каналы. Затем они отвечают обратно, используя очередь сообщений. Это не поможет решить проблему с пропускной способностью. но это значительно упростит передачу сообщений.
3. К вашему сведению, несколько лет спустя я переписал совместимый распределенный сервер на Erlang, на написание потребовалось меньше времени, чем на написание исходного сервера, и стало намного чище и проще. Кроме того, код составлял десятую часть от количества строк кода. У меня было гораздо меньше условий гонки, и дистрибутив встроен… Просто говорю 🙂