【问题标题】:What is a good session store for a single-host Node.js production app?对于单主机 Node.js 生产应用程序来说,什么是好的会话存储?
【发布时间】:2012-02-03 17:08:54
【问题描述】:

我正在使用带有 Connect 中间件的 Node Express。 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 是有意义的。

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

【问题讨论】:

  • 我使用的是 cookie-sessiosn,但是否有 sessiosn 数据存储在某处,因为在我的情况下发生的情况是当前会话只显示而不显示以前的会话??

标签: node.js express connect


【解决方案1】:

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

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

这是我用于 cookieSession 的咖啡脚本:

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

这是我用于 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
})

这是我的 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
    })
})

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

有关本地数据库基准,请参阅@Mustafa's answer

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

【讨论】:

  • 哇,很高兴看到数字。当然影响了我的决定。谢谢!
  • 顺便说一句,很高兴看到 MemoryStore 以这些为基准——有机会吗? ;)
  • 其实你应该在你的localhost中使用redis来做基准测试,远程使用redis显然很慢
  • 当然会慢一些,你用的是外部服务器!这个答案很大程度上是错误的!您正在将苹果与橙子进行比较..
  • @Mustafa 看到我的评论几个 cmets:stackoverflow.com/questions/8749907/…
【解决方案2】:

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

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

【讨论】:

  • 我使用的是 cookie-sessiosn,但是否有 sessiosn 数据存储在某处,因为在我的情况下发生的情况是当前会话只显示而不显示以前的会话??
【解决方案3】:

另一个不错的选择是 memcached。如果重新启动 memcached,会话状态会丢失,但实际上没有任何理由这样做。即使重新启动应用服务器,您也可以让缓存一直运行。对会话数据的访问几乎是即时的,无论您给它多少(适当的)内存,memcached 都会愉快地运行。而且我从未见过 memcached 崩溃(在 Linux 上)。

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

关于 memcached 的一般注意事项:

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

这些都不应该是会话存储的问题;仅使用通用缓存。

【讨论】:

  • 你知道如何将它插入连接中间件的会话处理程序吗? (我是这方面的n00b)
  • @Chocohound 你发现了吗……我可以连接到 Memcache 服务器……但是如何在环境文件中使用 memcache 配置会话存储?
  • 我使用的是 cookie-sessiosn,但是否有 sessiosn 数据存储在某处,因为在我的情况下发生的情况是当前会话只显示而不显示以前的会话??
  • github.com/expressjs/session 中所列,现在有一个 Memcached 会话存储 (connect-memcached) 可用:npmjs.com/package/connect-memcached
【解决方案4】:

我已经使用 connect-mongo 使用 MongoDB 会话存储。

使用npm install connect-mongo 安装并将现有的 MemoryStore 替换为

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

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

【讨论】:

    【解决方案5】:

    即使用于本地开发,我仍然会使用 Redis。这很有帮助,因为即使您重新启动 Node 应用程序,它也会存储会话,让您的浏览器会话保持登录状态。Redis 默认情况下将会话保存在内存中,就像连接的内存存储一样易于配置(我只是在屏幕中运行它我的节点应用程序)可以支持多个应用程序,如果您只是在配置中使用不同的数据库或会话值。

    【讨论】:

    • 我不会为 dev 和 prod 使用不同的商店,这样做无疑会遇到未捕获的错误。蒂姆是正确的,使用 redis 本地和生产。
    • 不过,如果你在 windows 盒子上开发,那就没那么有趣了。
    • 我使用的是 cookie-sessiosn,但是否有 sessiosn 数据存储在某处,因为在我的情况下发生的情况是当前会话只显示而不显示以前的会话??
    【解决方案6】:

    我自己只是在探索 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

    【讨论】:

    • 有趣的是,Ben Adida 实际上是我的一个朋友。小世界!
    • 我不是专家,但我认为普遍的共识是安全 cookie 不是……嗯……安全。我会做一些阅读,但我不想做任何尚未成为主流的事情。
    • 好吧,你总是可以去实现一个基于文件的简单会话存储——类似于 PHP 所做的。假设操作系统缓存文件,我猜你会得到合理的性能。或者你可以使用 tmpfs,它是内存支持的文件系统。
    • 似乎 cookie 会话现在是官方连接发行版的一部分,通过 the cookieSession middleware
    • 另一个要考虑的数据点。 Ruby on Rails 默认会话存储基于 Cookie (github.com/rails/rails/blob/master/actionpack/lib/…)。
    【解决方案7】:

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

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

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

    express-session 全功能 MemoryStore 模块无泄漏!

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

    我认为值得将此作为另一个答案发布,以防万一其他人像我最初那样犯了丢失记忆库的错误。

    【讨论】:

    • 谢谢!这就是我需要的
    【解决方案8】:

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

    【讨论】:

    • 我使用的是 cookie-sessiosn,但是否有 sessiosn 数据存储在某处,因为在我的情况下发生的情况是当前会话只显示而不显示以前的会话??
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-26
    • 1970-01-01
    • 2011-04-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多