Utilisation de MemoryStore en production


116

Aujourd'hui, j'ai exécuté mon application Node.js en mode "production" pour la première fois et j'ai reçu cet avertissement:

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

Je n'ai besoin d'exécuter qu'un seul processus, mais que dois-je utiliser à la place? Je veux que mes sessions résident dans la RAM pour un accès rapide. Je souhaite également pouvoir supprimer toutes les sessions en arrêtant simplement l'application Node.

Il semble exagéré d'installer Redis, MongoDB ou une autre base de données juste pour cette tâche simple. Je ne comprends pas non plus pourquoi MemoryStore est inclus dans Node alors qu'il ne devrait pas vraiment être utilisé?

Réponses:


29

MemoryStore est juste pour le mode de développement (rapide), car si votre application redémarre (le processus meurt), vous perdrez toutes les données de session (qui résidaient dans la mémoire de ce processus).

Si vous ne souhaitez pas utiliser de base de données, utilisez plutôt le stockage de cookies cryptés.

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


80

Ok, après avoir parlé aux développeurs de Connect, j'ai obtenu plus d'informations. Il y a deux choses considérées comme des fuites de mémoire ici:

  1. problème avec l'analyse JSON qui est déjà corrigé dans les versions récentes
  2. le fait qu'il n'y a pas de nettoyage des sessions expirées si les utilisateurs n'y accèdent jamais (c'est-à-dire que le seul nettoyage est à l'accès)

La solution semble assez simple, du moins c'est ce que je prévois de faire: utilisez setInterval pour nettoyer périodiquement les sessions expirées. MemoryStore fournit all () pour obtenir la liste, et nous pouvons utiliser get () pour forcer la lecture et ainsi les expirer. Pseudo-code:

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

Maintenant, appelez simplement sessionCleanup périodiquement via setInterval () et vous disposez d'un garbage collection automatique pour les sessions expirées. Fini les fuites de mémoire.


3
J'ai découvert que vous pouviez également utiliser Redis et Mongo comme magasin de sauvegarde et faire nettoyer la base de données. Dans le cas de Mongo, vous pouvez définir la date d'expiration tout en assurant l'indexation.
— huggie

57
C'est vraiment une chose stupide qu'ils ont faite en mettant ce message là. C'est comme "nous aurions pu faire les choses correctement, mais au lieu de cela, nous allons simplement faire des erreurs et vous allez jouer à un jeu de devinettes sur les internets. Ha ha! Perdants!"
— catamphétamine

2
quelle est la valeur du var sessionStore?
— Dimitri Kopriwa

4
sessionStore? Est-ce une variable globale node.js? Sinon, comment puis-je obtenir une référence au magasin de sessions dans node.js?
— Windchime

1
@MilanBabuskov - mettez-vous cela dans votre app.jsfichier? Existe-t-il une option pour émettre un rappel dans une session express? Un peu plus de détails sur la façon d'imposer ce serait génial.
— Jonathan Bechtel

46

Donc, la réponse acceptée à cette question est [modifier: était] à peu près un hack, et les autres recommandent simplement d'utiliser une base de données que je pense exagérée.

J'ai eu le même problème et je viens de remplacer express-session par cookie-session .

Pour ce faire, installez simplement cookie-session:

npm install cookie-session

Ensuite, dans votre app.js, recherchez où express-sessionest utilisé et remplacez-le par cookie-session.

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

Vous devrez peut-être changer d'autres choses, pour moi, c'était un simple échange de bobs-votre-oncle-sans-mal.


2
comment as-tu fais ça.
— Sid

2
C'est en fait une réponse utile. Merci.
— smonff

5
la différence est que cookie-sessionstocke les données sur le client, tandis que express-sessionstocke les données sur le serveur.
— George

11

Ce module a été conçu pour traiter le problème de fuite de mémoire. https://www.npmjs.com/package/session-memory-store

La réponse acceptée peut être bonne. Cependant, comme cette question apparaît en haut de la liste des résultats de recherche, j'ai pensé l'inclure au cas où cela aiderait quelqu'un d'autre.


Je n'ai pas essayé cela, mais cela ressemble à une excellente solution pour la situation (si OP est d'accord avec les sessions perdues au redémarrage de l'application)
— stujo

De votre lien: "Il est fortement déconseillé de l'utiliser en production!". La question concerne "l'utilisation de MemoryStore en production".
— Damien

Oui, mais uniquement parce que "vous ne pouvez pas partager la session avec d'autres processus ou un autre service". Cela signifie qu'il existe d'autres solutions plus pratiques. Mais cela résout le problème de fuite de mémoire, donc si cela ne vous concerne pas, vous pouvez l'utiliser et répond au problème de la question.
— Dovev Hefetz

7

Je pense que le consensus autour du Web est que la bonne façon serait d'utiliser effectivement une base de données pour cela, mais si vous êtes sûr que vous ne voulez pas faire cela, supprimez l'avertissement - l'avertissement n'est pas la loi.

Cependant, puisque vous et moi convenons tous les deux que la fuite de mémoire est un réel problème, il est difficile de justifier que redis est excessif, car cela résoudrait votre problème.

Je ne comprends pas non plus pourquoi MemoryStore est inclus dans Node alors qu'il ne devrait pas vraiment être utilisé

c'est un grand point - mais à cela je dirais que le nœud lui-même n'est que récemment devenu prêt pour la production . Certaines personnes ne seraient pas du tout d'accord avec l'idée que c'est le cas.


2
La suppression de l'avertissement ne fera pas disparaître la fuite de mémoire.
— Milan Babuškov

lol c'est pourquoi ils vous déconseillent de l'utiliser en production. donc l'alternative est d'utiliser une autre méthode de stockage, n'est-ce pas?
— Kristian

1
Je suppose que je n'aime tout simplement pas les alternatives que j'ai trouvées jusqu'à présent. Je recherche une alternative javascript simple en mémoire, pas un système de base de données. Je ne comprends vraiment pas pourquoi ils ne le réparent pas. Je veux dire, à quel point un simple magasin de mémoire peut-il être difficile ... J'espère juste que quelqu'un l'a déjà fait, donc je n'ai pas à réinventer la roue.
— Milan Babuškov

2
Je ressens votre douleur, mais le nœud est assez saignant en ce moment .. il vient en quelque sorte avec le territoire
— Kristian

7
MemoryStore n'est pas inclus dans Node, il est inclus dans Express / Connect
— Mustafa

6

L'alternative est d'utiliser Redis ou Mongo comme magasin. Avec Mongo, vous utilisez le module express-session-mongo .

Il existe un conseil pour supprimer les sessions obsolètes avec une option d'indexation:

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

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

Étant donné que les sessions obsolètes sont supprimées par la base de données elle-même, la session Express n'a pas besoin de gérer le nettoyage par elle-même.

EDIT : Il semble que vous deviez avoir votre propre champ "lastAccess". Lorsque vous y accédez, vous mettez à jour ce champ vous-même. Consultez la documentation MongoDB expire-data http://docs.mongodb.org/manual/tutorial/expire-data/

EDIT2 :

Devient maintenant db.sessions.createIndex( { "createdAt": 1 }, { expireAfterSeconds: 3600 } )

Le thread d'arrière-plan Mongo pour vérifier ce champ s'exécute toutes les 60 secondes. Le moment choisi pour retirer le document n'est donc pas exact.


2

Pour ceux qui ont des problèmes avec Redis, essayez ce qui suit - espérons que cela vous aidera.

J'utilise Redis pour DEV et PROD et je cible Express v4. Sous Windows, j'utilise le jeu d'outils léger MSOpenTech Redis v3.0, sinon, j'utilise simplement le module complémentaire Heroku Redis. Le faire fonctionner via Node n'a pas été trop difficile - jusqu'à présent ...

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

Bonne chance!

ps. Je viens de relire la requête originale et je l'ai remarqué - désolé!

Il semble exagéré d'installer Redis, MongoDB ou une autre base de données juste pour cette tâche simple.


0

Si vous utilisez OSX, utilisez

brew install memcached

si linux

apt install memcached

Résolvez le message de session, car l'application peut se connecter au service memcache 127.0.0.1:11211.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.