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

我使用的是 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 是有意义的。

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

50583 次浏览

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

我仍然会使用 Redis,即使是为了当地的发展。这很有帮助,因为即使在重新启动 Node 应用程序时,它也会存储会话,并保持浏览器会话的登录状态。Redis 默认将会话保存在内存中,就像 connect 的内存存储很容易配置一样(我只是在屏幕上运行它和我的节点应用程序) ,如果你只是在配置中使用不同的数据库或会话值,它可以支持多个应用程序。

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

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

关于 memcached 一般需要记住的事情:

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

对于会话存储来说,这两者都不是问题; 只是对于通用缓存而言。

我使用了一个使用 连接-蒙戈的 MongoDB 会话存储。

使用 npm install connect-mongo安装,并用

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

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

花了一整天调查这个。以下是我发现的几种选择。请求/秒通过 ab -n 100000 -c 1 http://127.0.0.1:9778/在我的本地机器上执行。

  • 没有会话-快(438要求/秒)
  • CookieSession : 不需要外部服务,速度影响较小(311 req/sec)-最快,会话将随 cookie (由 maxAge定制)过期
  • Connect-redis : 需要 redis 服务器,大速度影响(4 req/sec,redis2go 和 redisgreen)-比 mongo 更快,会话将在一段时间后被删除(由 ttl定制)
  • Connect-mongo -需要 mongodb 服务器,大的速度影响(2 req/sec with mongohq)-比 redis 慢,需要将手动 clear_interval设置为清理会话

以下是我在 cookie 会议上使用的咖啡脚本:

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

下面是我用来重温的咖啡脚本:

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 的回答

很高兴有人来 编辑这个答案添加他们的本地数据库基准组合。

由于接受的答案只是连接到远程主机,所以显然它总是比 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'
}));

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

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

我在另一个 Stack Overflow 线程中发现了 会话-内存-存储,它看起来不错,但显著增加了我的依赖项的大小。

最后,我找到了 记忆仓库 在 < a href = “ https://www.npmjs.com/package/Express-session”rel = “ nofollow noReferrer”> Express-session 的文档中。我最初错过了它,因为它的名字与默认的 MemoryStore类似,但它正是我所寻找的:

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

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

我认为这是值得张贴这作为另一个答案,只是以防其他人犯了错误,失去了记忆库,因为我最初这样做。