Использование MemoryStore в производстве


116

Сегодня я впервые запустил свое приложение Node.js в "производственном" режиме и получил следующее предупреждение:

Warning: connection.session() MemoryStore is not
designed for a production environment, as it will leak
memory, and obviously only work within a single process.

Мне нужно запустить только один процесс, но что мне использовать вместо этого? Я хочу, чтобы мои сеансы находились в оперативной памяти для быстрого доступа. Я также хочу иметь возможность отбрасывать все сеансы, просто закрывая приложение Node.

Кажется излишним устанавливать Redis, MongoDB или другую базу данных только для этой простой задачи. Я также не понимаю, почему MemoryStore включен в Node, когда его на самом деле не следует использовать?

Ответы:


29

MemoryStore предназначен только для (быстрого) режима разработки, потому что, если ваше приложение перезапустится (процесс умирает), вы потеряете все данные сеанса (которые находились в памяти этого процесса).

Если вы не хотите использовать базу данных, используйте зашифрованное хранилище файлов cookie.

http://www.senchalabs.org/connect/cookieSession.html


80

Хорошо, после разговора с разработчиками Connect я получил дополнительную информацию. Здесь утечками памяти считаются две вещи:

  1. проблема с парсингом JSON, которая уже исправлена ​​в последних версиях
  2. тот факт, что не выполняется очистка просроченных сеансов, если пользователи никогда не обращаются к ним (т.е. единственная очистка выполняется при доступе)

Решение кажется довольно простым, по крайней мере, это то, что я планирую сделать: использовать setInterval для периодической очистки просроченных сеансов. MemoryStore предоставляет all () для получения списка, и мы можем использовать get () для принудительного чтения и, таким образом, истечения срока их действия. Псевдо-код:

function sessionCleanup() {
    sessionStore.all(function(err, sessions) {
        for (var i = 0; i < sessions.length; i++) {
            sessionStore.get(sessions[i], function() {} );
        }
    });
}

Теперь просто периодически вызывайте sessionCleanup через setInterval (), и у вас есть автоматическая сборка мусора для просроченных сеансов. Больше никаких утечек памяти.


3
Я обнаружил, что вы также можете использовать Redis и Mongo в качестве резервного хранилища и очистить его от db. В случае Mongo вы можете установить дату истечения срока действия, обеспечивая индексацию.
— huggie

57
Они действительно сделали глупость, поместив это сообщение. Это похоже на «мы могли бы сделать это правильно, но вместо этого мы просто сделаем это неправильно, и вы пойдете поиграть в угадайку в Интернете. Ха-ха! Неудачники!»
— катамфетамин

2
каково значение var sessionStore?
— Дмитрий Коприва

4
sessionStore? Это глобальная переменная node.js? Если нет, как мне получить ссылку на хранилище сеансов в node.js?
— windchime

1
@MilanBabuskov - вы кладете это в свой app.jsфайл? Есть ли возможность выполнить обратный вызов внутри экспресс-сеанса? Было бы замечательно немного подробнее о том, как воспрепятствовать этому.
— Джонатан Бектел

46

Итак, принятый ответ на этот вопрос: [edit: was] в значительной степени был взломом, а другие просто рекомендуют использовать базу данных, что, на мой взгляд, является излишним.

У меня была такая же проблема, и я просто заменил экспресс-сеанс на cookie-сеанс .

Для этого просто установите cookie-session:

npm install cookie-session

Затем в вашем app.jsнайдите, где express-sessionиспользуется, и замените на cookie-session.

app.use(require('cookie-session')({
    // Cookie config, take a look at the docs...
}));

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


2
Как ты это делаешь.
— Сид,

2
На самом деле это полезный ответ. Thanx.
— smonff 01

5
разница в том, что cookie-sessionданные хранятся на клиенте, а express-sessionданные хранятся на сервере.
— Джордж

11

Этот модуль был разработан для решения проблемы утечки памяти. https://www.npmjs.com/package/session-memory-store

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


Не пробовал, но похоже, что это отличное исправление ситуации (если OP в порядке с потерянными сеансами при перезапуске приложения)
— stujo

По вашей ссылке: «Крайне не рекомендую использовать в продакшене!». Вопрос по поводу «Использование MemoryStore в продакшене».
— Дэмиен

Верно, но только потому, что «вы не можете поделиться сеансом с другим процессом или другой службой». То есть есть и другие, более практичные решения. Но это решает проблему утечки памяти, поэтому, если вас это не беспокоит, можно использовать и устранить проблему, связанную с вопросом.
— Довев Хефец

7

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

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

Я также не понимаю, почему MemoryStore включен в Node, когда его действительно не следует использовать

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


2
Подавление предупреждения не устранит утечку памяти.
— Милан Бабушков

lol, вот почему они не советуют вам использовать его в продакшене. так что альтернатива - использовать альтернативный метод хранения, не так ли?
— Кристиан

1
Думаю, мне просто не нравятся альтернативы, которые я нашел до сих пор. Я ищу простую альтернативу javascript в памяти, а не систему баз данных. Я действительно не понимаю, почему они не исправляют это. Я имею в виду, насколько сложным может быть простое хранилище памяти ... Я просто надеюсь, что кто-то уже сделал это, поэтому мне не нужно заново изобретать колесо.
— Милан Бабушков

2
Я чувствую вашу боль, но узел сейчас довольно передовой ... он вроде как идет с территорией
— Кристиан

7
MemoryStore не включен в Node, он включен в Express / Connect
— Мустафа

6

Альтернативный вариант - использовать Redis или Mongo в качестве магазина. В Mongo вы используете модуль express-session-mongo .

Есть совет удалить устаревшие сеансы с опцией индексирования:

var MongoStore = require('express-session-mongo');
app.use(express.session({ store: new MongoStore() }));

db.sessions.ensureIndex( { "lastAccess": 1 }, { expireAfterSeconds: 3600 } )

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

РЕДАКТИРОВАТЬ : Похоже, вам нужно иметь собственное поле "lastAccess". При доступе к нему вы сами обновляете это поле. Проверьте данные об истечении срока действия документации MongoDB http://docs.mongodb.org/manual/tutorial/expire-data/

РЕДАКТИРОВАТЬ2 :

Теперь становится db.sessions.createIndex( { "createdAt": 1 }, { expireAfterSeconds: 3600 } )

Фоновый поток Mongo для проверки этого поля запускается каждые 60 секунд. Таким образом, время удаления документа не точное.


2

Для тех, у кого проблемы с Redis, попробуйте следующее - надеюсь, это поможет.

Я использую Redis для DEV и PROD и нацелен на Express v4. В Windows я использую облегченный набор инструментов MSOpenTech Redis v3.0, в противном случае я просто использую Heroku Redis Addon. Заставить его работать через Node не так уж сложно - пока ...

var session = require('express-session');

. . .

var RedisStore = require('connect-redis')(session);

var redisClient = require('redis').createClient(process.env.REDIS_URL);

var redisOptions = { 
        client: redisClient, 
        no_ready_check: true,
        ttl: 600,
        logErrors: true
};

var redisSessionStore = new RedisStore(redisOptions);

app.use(session({
    store: redisSessionStore,
    secret: 'Some.Long.Series.of.Crazy.Words.and.Jumbled.letter.etc',
    resave: true,       
    saveUninitialized: true 
}));

Удачи!

пс. Я только что перечитал исходный запрос и заметил это - извините!

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


0

Если вы используете OSX, используйте

brew install memcached

если Linux

apt install memcached

решить сообщение сеанса, приложение может подключиться к 127.0.0.1:11211 службе memcache.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.