web-dev-qa-db-fra.com

Qu'est-ce qu'un bon magasin de sessions pour une application de production Node.js à hôte unique?

J'utilise le middleware Node's Express w/Connect. Le magasin de sessions mémoire de Connect n'est pas adapté à la production:

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

Pour les déploiements plus importants, mongo ou redis est logique.

Mais quelle est la bonne solution pour une application à hôte unique en production?

67
Nils

J'ai passé la journée à regarder ça. Voici les options que j'ai découvertes. Les requêtes/seconde sont effectuées via ab -n 100000 -c 1 http://127.0.0.1:9778/ sur ma machine locale.

  • pas de sessions - rapide (438 req/sec)
  • cookieSession : ne nécessite aucun service externe, impact mineur sur la vitesse (311 req/sec) - plus rapide, les sessions expireront avec le cookie (personnalisé par maxAge)
  • connect-redis : nécessite un serveur redis, un impact à grande vitesse (4 req/sec avec redis2go et redisgreen) - plus rapide que mongo, les sessions seront supprimées après un certain temps (personnalisé par ttl)
  • connect-mongo - nécessite un serveur mongodb, impact à grande vitesse (2 req/sec avec mongohq) - plus lent que redis, nécessite un manuel clear_interval à définir pour les sessions de nettoyage

Voici le coffeescript que j'ai utilisé pour cookieSession:

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

Voici le coffeescript que j'utilise pour 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
})

Voici mon coffeescript pour 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
    })
})

Maintenant, bien sûr, les bases de données distantes redis et mongo seront plus lentes que leurs équivalents locaux. Je n'arrivais tout simplement pas à faire fonctionner les équivalents locaux, d'autant plus que le temps d'installation et de maintenance pour moi était bien plus que ce que j'étais prêt à investir par rapport aux alternatives distantes hébergées, quelque chose que je pense être vrai pour d'autres aussi pourquoi ces services de base de données distants hébergés existent en premier lieu!

Pour les benhmarks de la base de données locale, voir @ réponse de Mustafa .

Heureux pour quelqu'un de modifier cette réponse pour ajouter ses repères de base de données locale au mélange.

83
balupton

Étant donné que la réponse acceptée se connecte uniquement aux hôtes distants, il est évident qu'elle sera toujours plus lente que localhost. Même s'il s'agit du prochain ordinateur de votre domicile, la lecture de cet ordinateur prendrait des millisecondes, mais la mémoire locale ne prend que des nanosecondes. Vous devez les comparer en utilisant des serveurs installés localement.

Voici mes résultats à partir de mon PC local: Vous voyez, redis est presque aussi rapide qu'en mémoire sous une charge élevée. Vous pouvez cloner le repo que ces codes de test sont 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] 

Les pages de session utilisées sont des pages très 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);
});

Configuration de la boutique Redis:

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

Configuration de la boutique Mongo:

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

Une autre bonne option est memcached. Les états de session sont perdus si memcached est redémarré, mais il n'y a pratiquement jamais de raison de le faire. Vous pouvez laisser le cache fonctionner tout le temps, même lorsque vous redémarrez votre serveur d'applications. L'accès aux données de la session est pratiquement instantané et le memcached fonctionnera parfaitement avec la quantité (appropriée) de mémoire que vous lui accordez. Et je n'ai jamais vu de crash memcached (sous Linux).

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

Choses à garder à l'esprit sur Memcached en général:

  • Ne jamais avoir d'espace dans vos clés de cache
  • N'oubliez pas qu'il existe une longueur de clé de cache maximale, y compris tout préfixe d'espace de noms que vous pourriez utiliser. Si votre clé de cache est trop longue, utilisez-la à la place.

Aucun de ces problèmes ne devrait être un problème avec le stockage de session; juste avec une mise en cache généralisée.

9
kgilpin

Je suis allé avec un magasin de sessions MongoDB en utilisant connect-mongo .

Installez avec npm install connect-mongo Et remplacez le MemoryStore existant par

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

Il gère automatiquement le côté base de données des sessions.

6
greenimpala

J'utiliserais toujours Redis même pour le développement local. Cela est utile car il stocke la session même lorsque vous redémarrez l'application Node, en gardant votre session de navigateur connectée. Redis par défaut enregistre la session en mémoire, de même que le magasin de mémoire de connect est simple à configurer (Je viens de l'exécuter à l'écran avec mes applications de nœud) peut prendre en charge plusieurs applications si vous utilisez simplement une base de données ou une valeur de session différente dans la configuration.

5
Timothy Meade

J'explore juste node.js moi-même, mais si vous n'avez pas besoin de stocker beaucoup d'informations dans l'objet de session - vous voudrez peut-être explorer les cookies sécurisés.

Les cookies sécurisés stockent les informations de session dans le cadre du cookie que le navigateur stocke et transfère à chaque demande. Ils sont cryptés pour empêcher un utilisateur de falsifier un cookie valide.

L'avantage est que vous n'avez pas à maintenir l'état sur le serveur - cette solution évolue bien et est simple à implémenter.

L'inconvénient est que vous ne pouvez stocker que jusqu'à environ 4 Ko et que les données sont envoyées au serveur sur chaque demande (mais vous pouvez avoir plusieurs domaines fictifs pointant sur votre serveur afin que vous n'imposiez pas ce bagage à du contenu statique visible publiquement, par exemple).

En recherchant sur le Web, il semble qu'il existe au moins deux implémentations de cookies sécurisés pour node.js. Je ne sais pas comment ils sont prêts pour la production, cependant:

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

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

3
nimrodm

Je comprends que c'est une vieille question, mais je l'ai rencontrée en cherchant une solution à un problème similaire. J'avais déjà décidé d'utiliser memcached pour le stockage de session sur Linux (avec connect-memcached ), mais j'avais également besoin de pouvoir exécuter sur Windows. J'ai passé un certain temps à essayer de trouver un stockage de session en mémoire pour une application de nœud à processus unique. Redis et Memcached ne semblent pas bien pris en charge sur Windows, et je ne voulais pas la complexité supplémentaire de leur installation.

J'ai trouvé session-memory-store dans un autre thread Stack Overflow, qui semble bon mais a considérablement augmenté la taille de mes dépendances.

Enfin, j'ai trouvé memorystore dans la documentation de express-session. Je l'avais manqué à l'origine en raison de la similitude de son nom avec le MemoryStore par défaut, mais c'est exactement ce que je cherchais:

module MemoryStore complet express-session sans fuites!

J'utilise maintenant connect-memcached lors de l'exécution dans un cluster (sous Linux uniquement) et memorystore lors de l'exécution d'un seul processus (sous Linux ou Windows).

J'ai pensé qu'il valait la peine de poster ceci comme une autre réponse, juste au cas où quelqu'un d'autre commettrait l'erreur de manquer le memorystore comme je l'ai fait initialement.

2
davidm_uk

Consultez mes benchmarks sur https://github.com/llambda/express-session-benchmarks montrant des comparaisons de différentes implémentations de session.

1
llambda