Usando MemoryStore en producción


116

Hoy ejecuté mi aplicación Node.js en modo "producción" por primera vez y recibí esta advertencia:

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

Solo necesito ejecutar un único proceso, pero ¿qué debo usar en su lugar? Quiero que mis sesiones residan en la RAM para un acceso rápido. También quiero poder descartar todas las sesiones simplemente cerrando la aplicación Node.

Parece una exageración instalar Redis, MongoDB u otra base de datos solo para esta simple tarea. Tampoco entiendo por qué MemoryStore está incluido en Node cuando en realidad no debería usarse.

Respuestas:


29

MemoryStore es solo para el modo de desarrollo (rápido), porque si su aplicación se reinicia (el proceso muere), perderá todos los datos de la sesión (que residían en la memoria de ese proceso).

Si no desea utilizar una base de datos, utilice el almacenamiento de cookies cifradas.

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


80

Bien, después de hablar con los desarrolladores de Connect, obtuve más información. Hay dos cosas que se consideran pérdidas de memoria aquí:

  1. problema con el análisis JSON que ya está solucionado en versiones recientes
  2. el hecho de que no hay limpieza de sesiones caducadas si los usuarios nunca acceden a ellas (es decir, la única limpieza es en el acceso)

La solución parece ser bastante simple, al menos esto es lo que planeo hacer: usar setInterval para limpiar periódicamente las sesiones caducadas. MemoryStore proporciona all () para obtener la lista, y podemos usar get () para forzar la lectura y así caducarlos. Pseudocódigo:

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

Ahora solo llame a sessionCleanup periódicamente a través de setInterval () y tendrá recolección automática de basura para las sesiones caducadas. No más pérdidas de memoria.


3
Descubrí que también puedes usar Redis y Mongo como una tienda de respaldo y hacer que la base de datos lo limpie. En el caso de Mongo, puede establecer la fecha de vencimiento y garantizar la indexación.
— huggie

57
Es realmente una estupidez que han hecho al poner este mensaje allí. Es como "podríamos haberlo hecho bien, pero en su lugar lo haremos mal y tú juegas un juego de adivinanzas en Internet. ¡Ja, ja! ¡Perdedores!"
— Catamphetamine

2
¿Cuál es el valor de var sessionStore?
— Dimitri Kopriwa

4
sessionStore? ¿Es una variable global de node.js? Si no es así, ¿cómo puedo obtener una referencia a la tienda de sesiones en node.js?
— carillón

1
@MilanBabuskov - ¿Pones esto en tu app.jsarchivo? ¿Existe una opción para emitir una devolución de llamada dentro de la sesión exprés? Un poco más de detalles sobre cómo mejorar esto sería genial.
— Jonathan Bechtel

46

Entonces, la respuesta aceptada a esto es [editar: era] prácticamente un truco, y los otros simplemente recomiendan usar una base de datos que creo que es excesiva.

Tuve el mismo problema y simplemente reemplacé express-session con cookie-session .

Para hacer esto, simplemente instale cookie-session:

npm install cookie-session

Luego, en su app.js, busque dónde express-sessionse está utilizando y reemplácelo con cookie-session.

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

Es posible que deba cambiar algunas otras cosas, para mí fue un simple intercambio de bobs-your-tío-sin-daño.


2
cómo hiciste eso.
— Sid

2
En realidad, esta es una respuesta útil. Gracias.
— smonff

5
la diferencia es que cookie-sessionalmacena los datos en el cliente, mientras que express-sessionalmacena los datos en el servidor.
— George

11

Este módulo fue diseñado para solucionar el problema de la pérdida de memoria. https://www.npmjs.com/package/session-memory-store

La respuesta aceptada puede estar bien. Sin embargo, dado que esta pregunta aparece en lo alto de la lista de resultados de búsqueda, pensé que la incluiría en caso de que ayude a alguien más.


No he probado esto, pero parece una gran solución para la situación (si OP está bien con sesiones perdidas en el reinicio de la aplicación)
— stujo

Desde su enlace: "¡No se recomienda usarlo en producción!". La pregunta es sobre "Uso de MemoryStore en producción".
— Damien

Correcto, pero solo porque "no puede compartir la sesión con otros procesos u otro servicio". Es decir, existen otras soluciones más prácticas. Pero esto resuelve el problema de la pérdida de memoria, por lo que si eso no le preocupa, entonces está bien usarlo y aborda la inquietud en la pregunta.
— Dovev Hefetz

7

Creo que el consenso en la web es que la forma correcta sería usar una base de datos para eso, pero si está seguro de que no quiere hacer eso, elimine la advertencia: la advertencia no es una ley.

Sin embargo, dado que usted y yo estamos de acuerdo en que la pérdida de memoria es un problema real, es difícil justificar decir que redis es excesivo, ya que resolvería su problema.

Tampoco entiendo por qué MemoryStore está incluido en Node cuando realmente no debería usarse

Ese es un gran punto, pero a eso diría que el propio nodo no ha estado listo para la producción recientemente . Algunas personas no estarían de acuerdo con la idea de que lo sea en absoluto.


2
Suprimir la advertencia no hará que la pérdida de memoria desaparezca.
— Milan Babuškov

lol es por eso que desaconsejan su uso en producción. así que la alternativa es utilizar un método alternativo de almacenamiento, ¿no es así?
— Kristian

1
Supongo que no me gustan las alternativas que encontré hasta ahora. Estoy buscando una alternativa simple de JavaScript en memoria, no un sistema de base de datos. Realmente no entiendo por qué no lo arreglan. Quiero decir, qué tan difícil puede ser una simple Memory Store ... Solo espero que alguien ya lo haya hecho, para no tener que reinventar la rueda.
— Milan Babuškov

2
Siento tu dolor, pero el nodo está bastante avanzado en este momento ... en cierto modo viene con el territorio
— Kristian

7
MemoryStore no está incluido en Node, está incluido en Express / Connect
— Mustafa

6

La alternativa es usar Redis o Mongo como tienda. Con Mongo usas el módulo express-session-mongo .

Existe un consejo para eliminar sesiones obsoletas con una opción de indexación:

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

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

Dado que las sesiones obsoletas son eliminadas por la propia base de datos, la sesión Express no necesita manejar la limpieza por sí misma.

EDITAR : Parece que necesita tener su propio campo "lastAccess". Cuando accedes a él, actualizas ese campo tú mismo. Consulte la documentación de MongoDB expire-data http://docs.mongodb.org/manual/tutorial/expire-data/

EDIT2 :

Ahora se convierte en db.sessions.createIndex( { "createdAt": 1 }, { expireAfterSeconds: 3600 } )

El hilo de fondo de Mongo para comprobar este campo se ejecuta cada 60 segundos. Entonces, el momento para eliminar el documento no es exacto.


2

Para aquellos que tienen problemas con Redis, intente lo siguiente: espero que esto ayude.

Estoy usando Redis para DEV y PROD y me dirijo a Express v4. En Windows, estoy usando el conjunto de herramientas ligero MSOpenTech Redis v3.0; de lo contrario, solo uso el complemento Heroku Redis. Hacer que funcione a través de Node no ha sido demasiado difícil, hasta ahora ...

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 
}));

¡Buena suerte!

PD. Acabo de volver a leer la consulta original y me di cuenta de esto: ¡lo siento!

Parece una exageración instalar Redis, MongoDB u otra base de datos solo para esta simple tarea.


0

Si usa OSX use

brew install memcached

si linux

apt install memcached

Resuelva el mensaje de sesión, becose de la aplicación se puede conectar al servicio 127.0.0.1:11211 Memcache.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.