什么是单主机Node.js生产应用程序的好会话存储?

时间:2012-01-05 21:14:41

标签: node.js express connect

我正在使用Node的Express w / Connect中间件。 Connect的内存会话存储不适合生产:

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

对于大型部署,mongo或redis是有意义的。

但对于生产中的单主机应用程序,什么是一个很好的解决方案?

8 个答案:

答案 0 :(得分:84)

花了一天时间研究这个。以下是我发现的选项。请求/秒通过我本地计算机上的ab -n 100000 -c 1 http://127.0.0.1:9778/执行。

  • 没有会话 - 快速(438 req / sec)
  • cookieSession:不需要外部服务,轻微速度影响(311 req / sec) - 最快,会话将随Cookie一起过期(由maxAge自定义)
  • connect-redis:需要redis服务器,速度影响大(4 req / sec,redis2go和redisgreen) - 比mongo快,会话将在一段时间后删除(由ttl自定义)
  • connect-mongo - 需要mongodb服务器,大速度影响(使用mongohq需要2 req / sec) - 比redis慢,需要手动clear_interval设置为清理会话

这是我用于cookieSession的coffeescript:

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

这是我用于redis的coffeescript:

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

这是mongo的coffeescript:

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

当然,远程redis和mongo数据库将比本地数据库慢。 我只是无法让当地的等价物工作,特别是考虑到我的安装和维护时间远远超过我与托管远程替代品相比我愿意投资的东西,我认为其他人也是如此,因此为什么这些托管的远程数据库服务首先存在!

对于本地数据库benhmarks,请参阅@Mustafa's answer

很高兴有人edit this answer将他们的本地数据库基准添加到组合中。

答案 1 :(得分:68)

由于接受的答案只是连接到远程主机,很明显它总是比localhost慢。即使它是您家中的下一台计算机,从该计算机读取也需要几毫秒,但本地内存只需几纳秒。您应该使用本地安装的服务器来比较它们。

以下是我本地电脑的结果:你看,在高负荷下,redis几乎和内存一样快。您可以克隆这些测试代码可用的仓库: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] 

会话使用的页面是非常简单的页面;

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

Redis商店配置:

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

Mongo商店配置:

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

答案 2 :(得分:9)

另一个好的选择是memcached。如果memcached重新启动,会话状态将丢失,但实际上从来没有任何理由这样做。即使重新启动应用服务器,也可以使缓存始终保持运行。对会话数据的访问几乎是即时的,并且memcached将以您提供的任何(适当的)内存量愉快地运行。我从来没有见过memcached崩溃(在Linux上)。

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

关于memcached的一般注意事项:

  • 缓存键中永远不会有空格
  • 请注意,存在最大缓存密钥长度,包括您可能使用的任何名称空间前缀。如果您的缓存键太长,请使用它的单向哈希值。

这些都不应该是会话存储的问题;只是使用广义缓存。

答案 3 :(得分:6)

我使用connect-mongo使用了MongoDB会话商店。

使用npm install connect-mongo安装并用

替换现有的MemoryStore

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

它自动管理会话的数据库端。

答案 4 :(得分:5)

我仍然会使用Redis进行本地开发。这很有用,因为它甚至在您重新启动Node应用程序时也会存储会话,保持您的浏览器会话登录。默认情况下Redis将会话保存在内存中,与connect的内存存储器配置相同(我只是运行它)如果你只是在配置中使用不同的数据库或会话值,那么在屏幕上和我的节点应用程序一起可以支持多个应用程序。

答案 5 :(得分:3)

我自己正在探索node.js,但如果你不需要在会话对象中存储大量信息 - 你可能想要探索安全的cookie。

安全cookie将会话信息存储为浏览器存储和转发每个请求的cookie的一部分。它们已加密,以防止用户伪造有效的cookie。

优点是您不必在服务器上维护状态 - 此解决方案可以很好地扩展并且易于实现。

缺点是您最多只能存储大约4KB的数据,并且每次请求都会将数据发送到服务器(但是您可以将多个虚构域指向您的服务器,这样您就不会例如,将行李放在公开可见的静态内容上。

在网上搜索似乎至少有两个针对node.js的安全cookie实现。但不确定他们的生产准备情况如何:

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

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

答案 6 :(得分:2)

我很欣赏这是一个老问题,但我在寻找类似问题的解决方案时遇到了它。我已经决定在Linux上使用memcached进行会话存储(使用connect-memcached),但我还要求能够在Windows上运行。我花了一些时间试图为单进程节点应用程序找到内存中的会话存储。 Redis和Memcached在Windows上似乎没有得到很好的支持,我不希望安装的额外复杂性。

我在另一个Stack Overflow线程中找到session-memory-store,这看起来不错,但显着增加了我的依赖项的大小。

最后,我在memorystore 的文档中找到了express-session 。我最初错过了它,因为其名称与默认MemoryStore类似,但它正是我所寻找的:

  

快速会话全功能MemoryStore模块没有泄漏!

我现在在集群中运行时使用connect-memcached(仅在Linux上运行),在运行单个进程时(在Linux或Windows上)使用内存存储。

我认为值得将此作为另一个答案发布,以防万一其他人犯错误,因为我最初错过了内存库。

答案 7 :(得分:1)

https://github.com/llambda/express-session-benchmarks查看我的基准测试,显示不同会话实施的比较。