什么是单主机Node.js生产应用程序的良好会话存储?
我正在使用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是有意义的。
但是,在生产中的单主机应用程序有什么好的解决scheme?
花了一天的时间来看这个。 这是我发现的选项。 请求/秒是通过本地机器上的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 /秒) – 比redis慢,需要手动
clear_interval
设置为清理会话
这里是我用于cookieSession的coffeescript:
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数据库将比本地数据库慢。 我只是无法得到本地的等值工作,特别是考虑到我的安装和维护时间远远超过我愿意投资的东西,而不是托pipe的远程替代品,我觉得其他人也是这样,因此为什么这些远程托pipe数据库服务首先存在!
对于本地数据库benhmarks,请参阅@穆斯塔法的答案 。
很高兴有人编辑这个答案 ,将他们的本地数据库基准添加到组合中。
由于接受的答案只是连接到远程主机,显而易见,它总是比本地主机慢。 即使是家中的下一台计算机,从该计算机读取也需要几毫秒的时间,但本地内存只需要几十秒。 您应该使用本地安装的服务器来比较它们。
这里是我的本地电脑的结果:你看,在高负载下,redis几乎和内存一样快。 你可以克隆我的回购,这些testing代码可用: 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商店configuration:
app.use(express.session({ store: new RedisStore({ host: 'localhost', port: 6379, db: 2, }), secret: 'hello' }));
Mongo商店configuration:
app.use(express.cookieParser()); app.use(express.session({ store: new MongoStore({ url: 'mongodb://localhost/test-session' }), secret: 'hello' }));
另一个好的select是memcached。 如果memcached被重新启动,会话状态会丢失,但实际上从来没有任何理由这样做。 即使重新启动应用程序服务器,您也可以始终保持caching运行。 访问会话数据实际上是瞬间的,memcached会随着你给它的任何(适当的)内存量而愉快地运行。 我从来没有见过memcached崩溃(在Linux上)。
https://github.com/elbart/node-memcache
一般情况下要记住关于memcached:
- 切勿在caching键中留有空白
- 请注意,有一个最大的caching密钥长度,包括您可能使用的任何名称空间前缀。 如果您的caching密钥太长,请使用它的单向散列。
这些都不应该是会话存储的问题。 只是泛化的caching。
我已经用了一个使用connect-mongo的MongoDB会话存储。
使用npm install connect-mongo
安装,并用现有的MemoryStorereplace
app.use(express.session({ store: new MongoStore({ db: 'some-database' }) }));
它自动pipe理会话的数据库端。
我甚至还会使用Redis进行本地开发。 这是有帮助的,因为即使在重新启动Node应用程序时,它也会保存会话,从而保持浏览器会话的login。默认情况下,Redis将会话保存在内存中,与connect的内存存储相同,configuration简单(我只是在屏幕上运行它我的节点应用程序)可以支持多个应用程序,如果您只是在configuration中使用不同的数据库或会话值。
我只是自己探索node.js,但是如果不需要在会话对象中存储大量信息 – 您可能需要探索安全的cookie。
安全cookie将会话信息存储为浏览器存储和转发每个请求的cookie的一部分。 它们被encryption以防止用户伪造一个有效的cookie。
优点是您不必在服务器上维护状态 – 此解决scheme可以很好地扩展并且易于实现。
缺点是你最多只能存储大约4KB的数据,并且每次请求都会将数据发送到服务器(但是你可以有多个虚构的域名指向你的服务器,所以你不要将这些行李强加给公开的静态内容,例)。
searchnetworking似乎有至less两个node.js的安全cookie的实现。 不知道他们是如何生产的,
https://github.com/benadida/node-client-sessions/blob/master/lib/client-sessions.js