Всем привет. Хотелось бы проконсультироваться по ряду вопросов.
Имеется некий проект, построенный на микросервисной архитектуре.
Каждый микросервис имеет под собой два сервера - один для его работы, а второй для его базы данных.
Работа связана с геолокацией - обмен геоданными в режиме реального времени.
1. Целесообразно ли вводить "кэширование" тех пользователей, что в сети, на отдельном микросервисе, удаляя тех, кто отключился от сокет-серверов? Кэширование - просто хранение пользователей как JSON.
2. Отдача маркеров остальных пользователей одному из них происходит только если регистрируется изменение координат или границ карты. Для вычисления тех, что попадают используется формула (mp.B.X-mp.A.X) * (mark.Y-mp.A.Y) - (mp.B.Y - mp.A.Y) * (mark.X-mp.A.X).
Следовательно, пользователи "прогоняются" в цикле и отправляются тем, у кого они попадают. Но если будет тот же 1 млн пользователей в сети, я думаю, что такими темпами сервер скоро откинет копыта. Как можно улучшить?
1. непонятна схема взаимодействия "микросервисов", почему возник такой вопрос, почему нельзя на сокет-сервере держать пользователей?
2. циклы можно подкрутить, если возлагать обмен на низкоуровневые потоки и события, для миллиона клиентов поднимаются несколько серверов с группировкой и балансировкой.
Сергей Сергей, тогда вопрос следующий.
Каким образом можно ввести горизонтальное масштабирование Node.JS с Socket.IO, чтобы данные о сокетах были доступны для всех серверов?
теоретическая прикидка
На головном сервере есть некоторые сведения о всех пользователях и метках с указанием, какому сокет-серверу они принадлежат. Головной сервер сообщает сокет-серверам, какой из них обладает интересующими их пользователями и метками. Так сокет-серверы о пользователях и метках будут общаться между собой. Сообщение от одного пользователя до другого пойдет или через общий сокет-сервер, или через два сокет-сервера, которые уже будут знать об этих двух пользователях.
Стоит подумать над тем, есть ли в логике приложения прямые запросы от пользователей друг к другу, которые невозможно предсказать, такие запросы будут проходить через головной сервер и порождать поиск.
Конечно, всё обрушится, когда пользователи и метки все вместе окажутся внутри какой-то минимальной зоны.
Вычисления критериев на "попадание" придется как-то разделить. Например, распределить пользователей и метки по зонам, по степени удалённости зон исключать вычисления.
Сергей Сергей, а потом при той же отправке сообщения можно будет использовать нечто вроде:
socket.on('send message', function(data){
var get_options = {
method: 'GET',
uri: 'https://ss1.example.com/getServer:'+data.userID+''
};
request(get_options)
.then(function(response){
// Здесь парсим полученный от головного сервера JSON и вытаскиваем из него сервер другого клиента, а далее отправляем на другой сервер API запрос, показывая, что нам нужно отобразить сообщение для пользователя userID
})
.catch(function(err){
// Обрабатываем ошибку, если не удалось достучаться до головного
});
Я Вас верно понял?
Ну и, помимо этого, хранить на каждом сокет-сервере список пользователей, которые к нему подключены и искать перво-наперво среди них, чтобы не дергать API без повода. Верно?
Сергей Сергей, а при присоединении нового пользователя, соответственно, сохраняем его в "кэше" нашего сервера, а так же отправляем запрос на регистрацию пары ключ=>значение (userID=>serverID) на головной сервер. Все правильно?
API в виде протокола обмена — между серверами постоянное соединение логичнее держать.
Запросы на поиск пользователей по идентификатору надо свести к минимуму. Тем более, что о видимости между пользователями обычно должно быть уже известно сокет-серверам после вычислений "попадания". И гадать, куда обращаться к пользователю не придётся — хранимые на сокет-серверах списки о пользователях ведь с такой меткой и предусматриваются.
Да, подключающиеся пользователи запоминаются на сокет-сервере и на головном. И (повторю) при надобности осведомляются остальные "заинтересованные" в ходе вычислений сокет-серверы. Привязка сокет-сервера и пользователя по идентификаторам есть "корень" такого взаимодействия.
Ещё нужно много продумать о вычислениях "попаданий", какие данные понадобятся головному серверу, где вычислять получится быстрее, прочие неочевидности.
По поводу "кэша" на пользователей. Как-то особенно их запоминать по-моему незачем, если отвалится сокет-сервер или один из "воркеров" на нём, то и отвалятся пользователи, они будут сами реконнектиться к любому другому серверу. На головном сервере нужно будет как-то разрешать последующие нестыковки, но здесь уже полноценное хранилище будет.
для улучшения поиска коллизий полно алгоритмов, обычно они ориентированны на то чтоб "ПОЛЕ" разделить на сектора, и искать коллизии только внутри точек с общими секторами.
в рамках микросервисной архитектуры каждый "микросервис" может обслуживать свой небольшой сектор.
ваша задача найти выгодную схему нарезания на сектора, предположу что нужно будет использовать алгоритм хэширования (разделения на сектора) с двумя переменными такие как (размер и расположение сектора и его средняя загрузка, чтоб в среднем была равная загрузка секторов на обработку данных), наилучшую формулу вам нужно будет найти опытным путем.
есть само собой и другие подходы.
не вижу какой-то необходимости что-то с пользователями кэшировать. Лучше обеспечте локальность данных, тоесть размещайте данные (БД) в том же самом месте где их и обрабатывайте, это главное правило для масштабируемой и производительной архитектуры построенной на микросервисах.