72 votes

Quel est un bon magasin de session pour une application de production Node.js à hôte unique ?

J'utilise Express de Node avec l'intergiciel Connect. La mémoire de session de Connect n'est pas adaptée à 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 plus judicieux.

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

86voto

balupton Points 17805

J'ai passé la journée à étudier la question. 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.

  • aucune session - rapide (438 req/sec)
  • cookieSession : ne nécessite aucun service externe, impact mineur sur la vitesse (311 req/sec) - le plus rapide, les sessions expireront avec le cookie (personnalisé par maxAge )
  • connecter-redis : nécessite un serveur redis, impact important sur la 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, ce qui a un impact important sur la vitesse (2 req/sec avec mongohq) - plus lent que redis, nécessite un entretien manuel clear_interval à mettre en place pour nettoyer les sessions

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

Bien entendu, les bases de données redis et mongo distantes seront plus lentes que leurs équivalents locaux. Je n'arrivais tout simplement pas à faire fonctionner les équivalents locaux, surtout si l'on considère que le temps d'installation et de maintenance était pour moi bien plus important que ce que j'étais prêt à investir par rapport aux alternatives à distance hébergées, ce qui est vrai pour d'autres aussi, d'où l'existence de ces services de bases de données à distance hébergées !

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

Heureux que quelqu'un modifier cette réponse d'ajouter leurs repères locaux de base de données au mélange.

79voto

Mustafa Points 2782

Puisque la réponse acceptée ne se connecte qu'aux hôtes distants, il est évident qu'elle sera toujours plus lente que localhost. Même s'il s'agit de l'ordinateur le plus proche de chez vous, il faudra des millisecondes pour lire sur cet ordinateur, alors que la mémoire locale ne prend que des nanosecondes. Vous devriez les comparer en utilisant des serveurs installés localement.

Voici mes résultats sur mon ordinateur local : Vous voyez, redis est presque aussi rapide que in-memory en cas de charge élevée. Vous pouvez cloner mon repo où 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 utilisées lors de la session 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 du magasin Redis :

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

Configuration du magasin Mongo :

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

9voto

kgilpin Points 828

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

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

Les choses à garder à l'esprit à propos de memcached en général :

  • Ne jamais avoir d'espace dans vos clés de cache
  • Sachez qu'il existe une longueur maximale de clé de cache, y compris tout préfixe d'espace de nom que vous pourriez utiliser. Si votre clé de cache est trop longue, utilisez plutôt un hachage à sens unique de celle-ci.

Ni l'un ni l'autre ne devrait être un problème avec le stockage de session, mais seulement avec la mise en cache généralisée.

7voto

greenimpala Points 1081

J'ai opté pour un magasin de session MongoDB en utilisant connect-mongo .

Installer avec npm install connect-mongo et remplacer 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.

5voto

Timothy Meade Points 1028

Je continuerais à utiliser Redis même pour le développement local. C'est utile car il stocke la session même lorsque vous redémarrez l'application Node, en gardant la session de votre navigateur connectée. Par défaut, Redis enregistre la session en mémoire, comme le magasin de mémoire de connect. Il est simple à configurer (je l'exécute simplement à l'écran avec mes applications Node) et peut supporter plusieurs applications si vous utilisez simplement une base de données ou une valeur de session différente dans la configuration.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X