const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
console.log(`Master ${process.pid} is running`);
// Fork workers.
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`worker ${worker.process.pid} died`);
});
} else {
// Workers can share any TCP connection
// In this case it is an HTTP server
var sticky = require('sticky-session');
var express = require('express');
var app = express();
app.get('/', function (req, res) {
console.log('worker: ' + cluster.worker.id);
res.send('Hello World!');
});
var server = http.createServer(app);
sticky.listen(server,3000);
console.log(`Worker ${process.pid} started`);
}
我查阅了有关nodejs集群和粘性会话的文档 另一个与此有关的堆栈溢出答案
var cluster = require('cluster');
var http = require('http');
var sticky = require('sticky-session');
var express = require('express');
var app = express();
app.get('/', function (req, res) {
console.log('worker: ' + cluster.worker.id);
res.send('Hello World!');
});
var server = http.createServer(app);
sticky.listen(server,3000);
如果上面的代码段没有分叉地运行,则可以正常工作,但不能正常工作,如上面的集群示例所示,在该示例中,线程已启动,但服务器从未初始化。
我阅读了粘性集群的替代方法,有人可以对此主题给出适当的权威性答案,这对于寻找相同主题的人们将是有用的,另一个主要问题是app.locals对象,该对象用于存储一个应用程序实例的变量,并且多个服务器实例的出现会导致此中断,因为不同实例之间的值会不同,因此此方法会导致一个大问题,导致应用程序中断,因此。请回答时请不要复制粘贴一些代码,请提供详细信息详细回答该方法的好处和短处。
我不是在寻找限于使用粘性会话nodejs模块的答案,我欢迎使用处理器所有内核并确保会话连续性的所有其他方法。
如果涉及RedisStore或MongoDb存储就可以了,我想知道的是关于具有会话连续性群集的nodejs应用程序的标准方法
https://github.com/indutny/sticky-session
答案 0 :(得分:1)
我认为您将粘性会话与共享内存存储区混淆了。
让我尝试帮助:
实施粘性会话意味着您现在具有多个接受连接的节点。但是,它不不能保证这些节点将共享相同的内存,因为每个工作程序都有自己的事件循环和内部内存状态。
换句话说,一个节点正在处理的数据可能对其他工作节点不可用,这解释了您指出的问题。
...另一个主要问题是app.locals对象 用于存储应用实例和实例的变量 多个服务器实例导致此中断,因为值将是 在不同情况下会有所不同,因此这种方法会导致 问题和应用中断...
因此,要解决此问题,我们将需要使用 Redis 之类的东西,以便可以在多个节点之间共享数据。
希望这会有所帮助!
答案 1 :(得分:0)
如果我正确理解了您的问题,则说明您正在处理内存中的数据存储或会话存储。这是多节点或群集中基于会话的身份验证中的已知问题之一。假设您对节点A进行了调用,并获得了名为sessionA的会话,但是对于下一个调用,您对节点B进行了调用。节点B对会话A一无所知。人们尝试通过使用粘性会话来解决此问题,但这还不够。优良作法是使用替代方法,例如JWT或oAuth2。与服务通信相比,我更喜欢JWT。 JWT不存储任何内容且无状态。由于REST也是无状态的,因此它可与REST完美配合。这里的https://tools.ietf.org/html/rfc7519是JWT实现的规范。如果您需要某种刷新令牌,则需要考虑存储。存储可以是REDIS,MongoDB或任何其他基于SQL的数据库之类的东西。有关nodejs中JWT的进一步说明:
https://www.npmjs.com/package/jsonwebtoken
https://cloud.google.com/iot/docs/how-tos/credentials/jwts#iot-core-jwt-refresh-nodejs
答案 2 :(得分:-1)
您的代码中有一个小问题。 “ 粘性会话”模块已在其中使用了node.js的“ 集群”模块。您无需“ fork()”,因为粘性-会议已经为您完成。让我们看看如何:
var cluster = require('cluster'); // Only required if you want the worker id
var sticky = require('sticky-session');
var server = require('http').createServer(function(req, res) {
res.end('worker: ' + cluster.worker.id);
});
sticky.listen(server, 3000);
调用sticky.listen()已经为您生成了工作程序。请参见下面的listen()实现
function listen(server, port, options) {
if (!options)
options = {};
if (cluster.isMaster) {
var workerCount = options.workers || os.cpus().length;
var master = new Master(workerCount, options.env);
master.listen(port);
master.once('listening', function() {
server.emit('listening');
});
return false;
}
return true;
}
此行var master = new Master(workerCount,options.env)负责产生工作者。 请参见下面的Master()实现:
function Master(workerCount, env) {
net.Server.call(this, {
pauseOnConnect: true
}, this.balance);
this.env = env || {};
this.seed = (Math.random() * 0xffffffff) | 0;
this.workers = [];
debug('master seed=%d', this.seed);
this.once('listening', function() {
debug('master listening on %j', this.address());
for (var i = 0; i < workerCount; i++)
// spawning workers
this.spawnWorker();
});
}
因此,实际上,当您调用sticky.listen(server,port)时,实际上是在调用cluster.fork()。因此,您不应该再次明确地调用fork()。 现在您的代码应如下所示:
var cluster = require('cluster'); // Only required if you want the worker id
var sticky = require('sticky-session');
var server = require('http').createServer(function(req, res) {
res.end('worker: ' + cluster.worker.id);
});
//sticky.listen() will return false if Master
if (!sticky.listen(server, 3000)) {
// Master code
server.once('listening', function() {
console.log('server started on 3000 port');
});
} else {
// Worker code
}
要记住的重要一件事是,生成的工作人员将拥有自己的 EVENTLOOP 和内存,因此资源之间不会共享。 您可以使用“ REDIS”或其他npm模块(例如“ memored”)在不同工作人员之间共享资源。
希望这可以解决您的两个问题。