Как при распараллеливании nodejs приложения по разным серверам иметь единый массив пользовательских сессий?

Раньше, когда запросов к приложению было мало, всё работало на одном сервере, а пользовательские сессии хранились просто в переменных среды. Но теперь нагрузка упятерилась и встал вопрос о масштабировании. Какой способ будет наиболее быстр в плане доступа с серверов к единым пользовательским данным?
  • Вопрос задан
  • 2465 просмотров
Решения вопроса 1
MarcusAurelius
@MarcusAurelius Куратор тега Node.js
автор Impress Application Server для Node.js
Самое лучшее, это держать сессии и общее состояние (например, модель игрового мира или машину состояний, используемую для управления объектом промышленной автоматизации и т.д.) в оперативной памяти. Сессии только в одном процессе, а общее состояние в каждом процессе. Чтобы клиент подключался всегда к тому процессу, в котором лежит его сессия, то соединение должно быть подписано специальной cookie с номером процесса, кука эта может устанавливаться при аутентификации и после этого, сетевой маршрутизатор или реверс-прокси будет передавать все запросы, помеченные этой кукой, именно в нужный процесс. Но процессы дохнут периодически, поэтому сессии нужно сохранять в БД, но лучше это делать в ленивом (lazy) режиме, т.е. не во время HTTP запроса от клиента, а поставить периодическое событие и сбрасывать из памяти в БД, и иметь механизм восстановления из БД. Если процесс пользователя погиб, то при первом следующем запросе состояние восстановится и дальше будет опять браться из памяти. Можно сделать упреждающее чтение, если процесс погибает, то в БД хранить для каждого процесса массив пользователей, чье состояние он обрабатывал и сразу после повторного запуска, процесс восстановит из БД все сессии и будет ждать "своих" пользователей. Что касается общего для многих пользователей состояния, то его можно синхронизировать между процессами при помощи нехитрого API, пересылающего лог изменений состояния из того процесса, в котором они произошли во все другие при помощи IPC, HTTP или ZeroMQ. Пример такого API вот тут: https://github.com/tshemsedinov/impress/blob/maste... Вкратце, оно имеет функции inc(path, value, delay); dec(path, value, delay); set(path, value, delay); get(path); delete(path, delay); и т.д. тут path - это путь к данным в объекте состояния, например inc('myCar.speed', 15, "2s") - увеличить скорость машины в модели на 15 с гарантированной синхронизацией между процессами в течении 2 секунд (это для того, чтобы сократить кол-во пересылок изменений, они склеятся в течении 2 секунд). Все inc/dec изменения аддитивны в любом порядке, поэтому их можно пересылать как угодно, а в другом процессе можно подписаться на изменение subscribe('myCar.speed', function(path, value, remote) { ... }); где path - 'myCar.speed', value - новое значение, remote - true если изменение из другого процесса. Думаю, что Вы найдете и более подходящие реализации, но пример должен быть понятен. Можно конечно держать и сессии и общее состояние в БД, например в MongoDB, но это приводит к тому, что во время HTTP запросов случается I/O, и запрос ждет, а согласитесь, что ни какого I/O это быстрее, чем асинхронное I/O, брать из памяти - всегда лучше, а синхронизировать в свободное время (пусть с ограниченной точностью, с отставанием), а если личные сессии, то ни какого отставания вообще нет.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 2
Boniface
@Boniface
Добрый день! Храните сессии в memcashed или redis. Я redis использую.
Ответ написан
Комментировать
@hats
Если вы используете Express и MongoDB, то даже делать почти ничего не придется.
Подключаете пакеты:
session = require 'express-session'
mongoStore = require('connect-mongo')(session)
mongoose = require 'mongoose'

И при конфигурировании сессии пишете:
app.use session
    store: new mongoStore(mongoose_connection: mongoose.connection)


Не сомневаюсь, что что-то подобное есть и для memcashed c redis. Но мне пока монги хватает.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы