¿Qué es una buena tienda de sesión para una aplicación de producción Node.js de un solo servidor?

Estoy usando el middleware Express w / Connect de Node. La tienda de sesión de memoria de Connect no es apta para producción:

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

Para implementaciones más grandes, mongo o redis tiene sentido.

Pero, ¿cuál es una buena solución para una aplicación de host único en producción?

Pasé el día investigando esto. Estas son las opciones que he descubierto. Las solicitudes / segundo se realizan a través de ab -n 100000 -c 1 http://127.0.0.1:9778/ en mi máquina local.

  • sin sesiones – rápido (438 req / seg)
  • cookieSession : no requiere servicio externo, menor impacto de velocidad (311 req / s) – más rápido, las sesiones caducarán con la cookie (personalizada por maxAge )
  • connect-redis : requiere servidor redis, gran impacto de velocidad (4 req / seg con redis2go y redisgreen) – más rápido que mongo, las sesiones se eliminarán después de un tiempo (personalizado por ttl )
  • connect-mongo – requiere servidor mongodb, impacto de gran velocidad (2 req / seg con mongohq) – más lento que redis, requiere el clear_interval manual clear_interval para las sesiones de limpieza

Aquí está el coffeescript que utilicé para cookieSession:

 server.use express.cookieSession({ secret: appConfig.site.salt cookie: maxAge: 1000*60*60 }) 

Aquí está el coffeescript que uso para redis:

 RedisSessionStore ?= require('connect-redis')(express) redisSessionStore ?= new RedisSessionStore( host: appConfig.databaseRedis.host port: appConfig.databaseRedis.port db: appConfig.databaseRedis.username pass: appConfig.databaseRedis.password no_ready_check: true ttl: 60*60 # hour ) server.use express.session({ secret: appConfig.site.salt cookie: maxAge: 1000*60*60 store: redisSessionStore }) 

Aquí está mi coffeescript para mongo:

 server.use express.session({ secret: appConfig.site.salt cookie: maxAge: 100*60*60 store: new MongoSessionStore({ db: appConfig.database.name host: appConfig.database.host port: appConfig.database.port username: appConfig.database.username password: appConfig.database.password auto_reconnect: appConfig.database.serverOptions.auto_reconnect clear_interval: 60*60 # hour }) }) 

Ahora, por supuesto, las bases de datos redis y mongo remotas serán más lentas que sus equivalentes locales. Simplemente no pude hacer funcionar los equivalentes locales, especialmente teniendo en cuenta que el tiempo de instalación y mantenimiento para mí fue mucho más de lo que estaba dispuesto a invertir en comparación con las alternativas remotas alojadas, algo que siento que también es cierto para los demás. servicios de bases de datos existen en primer lugar!

Para conocer las bases de datos locales, consulte la respuesta de @Mustafa.

Feliz de que alguien edite esta respuesta para agregar sus puntos de referencia de bases de datos locales a la mezcla.

Como la respuesta aceptada solo se conecta a hosts remotos, es obvio que siempre será más lenta que localhost. Incluso si es la próxima computadora en su hogar, tomaría milisegundos leer desde esa computadora, pero la memoria local solo demora unos nanosegundos. Debe compararlos mediante el uso de servidores instalados localmente.

Aquí están mis resultados de mi PC local: Verá, redis es casi tan rápido como en la memoria en alta carga. Puede clonar mi informe de que estos códigos de prueba están disponibles: https://github.com/mustafaakin/express-session-store-benchmark

 Concurrency: 1 none 4484.86 [#/sec] memory 2144.15 [#/sec] redis 1891.96 [#/sec] mongo 710.85 [#/sec] Concurrency: 10 none 5737.21 [#/sec] memory 3336.45 [#/sec] redis 3164.84 [#/sec] mongo 1783.65 [#/sec] Concurrency: 100 none 5500.41 [#/sec] memory 3274.33 [#/sec] redis 3269.49 [#/sec] mongo 2416.72 [#/sec] Concurrency: 500 none 5008.14 [#/sec] memory 3137.93 [#/sec] redis 3122.37 [#/sec] mongo 2258.21 [#/sec] 

Las páginas de sesión utilizadas son páginas muy simples;

 app.get("/", function(req,res){ if ( req.session && req.session.no){ req.session.no = req.session.no + 1; } else { req.session.no = 1; } res.send("No: " + req.session.no); }); 

Configuración de la tienda Redis:

 app.use(express.session({ store: new RedisStore({ host: 'localhost', port: 6379, db: 2, }), secret: 'hello' })); 

Configuración de la tienda Mongo:

 app.use(express.cookieParser()); app.use(express.session({ store: new MongoStore({ url: 'mongodb://localhost/test-session' }), secret: 'hello' })); 

Otra buena opción es memcached. Los estados de la sesión se pierden si se reinicia memcached, pero prácticamente nunca hay ninguna razón para hacerlo. Puede dejar el caché en ejecución todo el tiempo, incluso cuando reinicie su servidor de aplicaciones. El acceso a los datos de la sesión es prácticamente instantáneo y la memcached funcionará felizmente con la cantidad de memoria (apropiada) que le dé. Y nunca he visto el locking de memcached (en Linux).

https://github.com/elbart/node-memcache

Cosas a tener en cuenta acerca de memcached en general:

  • Nunca tener espacios en blanco en las teclas de su caché
  • Tenga en cuenta que hay una longitud máxima de clave de caché, incluido cualquier prefijo de espacio de nombre que pueda usar. Si su clave de caché es demasiado larga, use un hash unidireccional en su lugar.

Ninguno de estos debe ser un problema con el almacenamiento de la sesión; solo con el almacenamiento en caché generalizado.

He ido con una tienda de sesión de MongoDB usando connect-mongo .

Instalar con npm install connect-mongo y reemplazar la MemoryStore existente con

app.use(express.session({ store: new MongoStore({ db: 'some-database' }) }));

Gestiona el lado de la base de datos de las sesiones automáticamente.

Todavía usaría Redis incluso para el desarrollo local. Esto es útil porque almacena la sesión incluso cuando reinicia la aplicación Node, manteniendo la sesión de su navegador conectada. Redis de forma predeterminada guarda la sesión en la memoria, al igual que el almacenamiento de memoria de connect es fácil de configurar (solo lo ejecuto en la pantalla junto con mis aplicaciones de nodos) pueden admitir múltiples aplicaciones si solo usa una base de datos diferente o valor de sesión en la configuración.

Solo estoy explorando node.js, pero si no necesitas almacenar mucha información en el objeto de la sesión, es posible que desees explorar las cookies seguras.

Las cookies seguras almacenan la información de la sesión como parte de la cookie que el navegador almacena y reenvía con cada solicitud. Están encriptados para evitar que un usuario falsifique una cookie válida.

La ventaja es que no tiene que mantener el estado en el servidor; esta solución se escala bien y es fácil de implementar.

La desventaja es que solo puede almacenar hasta 4 KB y que los datos se envían al servidor en cada solicitud (pero puede tener múltiples dominios ficticios apuntando a su servidor para que no imponga ese equipaje en contenido estático visible públicamente, para ejemplo).

Al buscar en la web, parece que hay al menos dos implementaciones de cookies seguras para node.js. Sin embargo, no estoy seguro de qué tan preparados estén para la producción:

https://github.com/benadida/node-client-sessions/blob/master/lib/client-sessions.js

https://github.com/caolan/cookie-sessions

Consulte mis benchmarks en https://github.com/llambda/express-session-benchmarks mostrando comparaciones de diferentes implementaciones de sesión.

Aprecio que esta es una vieja pregunta, pero me encontré con ella mientras buscaba una solución a un problema similar. Ya había decidido usar memcached para el almacenamiento de la sesión en Linux (con connect-memcached ), pero también requería la posibilidad de ejecutarlo en Windows. Pasé un tiempo tratando de encontrar un almacenamiento de sesión en memoria para una aplicación de nodo de proceso único. Redis y Memcached no parecen tener un buen soporte en Windows, y no quería la complejidad adicional de su instalación.

Encontré session-memory-store en otro subproceso de Stack Overflow, que se ve bien pero aumentó significativamente el tamaño de mis dependencias.

Finalmente, encontré memorystore en la documentación para la sesión expresa . Me lo había perdido originalmente debido a su nombre similar a MemoryStore predeterminado, pero es exactamente lo que estaba buscando:

¡módulo de MemoryStore con todas las funciones de sesión expresa sin fugas!

Ahora estoy utilizando connect-memcached cuando se ejecuta en un clúster (solo en Linux) y memorystore cuando ejecuto un único proceso (en Linux o Windows).

Pensé que valía la pena publicar esto como otra respuesta, solo en caso de que alguien más cometa el error de perder la memoria de almacenamiento como lo hice inicialmente.

    Intereting Posts