node app.js
时,运行的进程只有1个线程。然而,它运行的时间越长,为该进程创建的线程就越多。问题在于,当我想要执行特定类型的代码时,例如:var io = require('socket.io')(process.env.PORT);
它失败了,因为信号来自多个线程,因此代码没有成功执行。
简单的测试,如果有人这样做:
var io = require('socket.io')(9001);
var io = require('socket.io')(9002);
var io = require('socket.io')(9003);
var io = require('socket.io')(9004);
它能够正常工作,但是这段代码:
var cPort = 9001;
setInterval(function() {
var io = require('socket.io')(cPort);
cPort++;
}, 1000 * 60 * 2); // 1 sec * 60 seconds * 2 = 2 minutes interval
由于在2分钟后,节点将有许多线程并且它们都尝试执行代码,因此不会执行代码-结果您将看到错误:地址正在使用
。
那么,尽管运行了同一文件的多线程进程,我如何强制节点仅执行此代码一次?
06.11.2017 编辑 ----
澄清问题:
我的意思是,在问题上,我没有资源问题,如果我同时启动所有服务器(例如40个服务器),它们都可以成功启动并无限期地工作。如果我只启动一个服务器,然后运行自动启动更多服务器的代码,则此时总是会出现地址正在使用
错误,当然显然在代码执行时地址没有被占用。目前,当人们使用服务较多并且一周中的其他日子里服务器较少时,我必须在周末手动启动更多服务器,我希望创建基于人口的自动化系统,以启动和关闭服务器。
这是服务器启动的代码:
var cp = require('child_process'),
servers = [],
per_server = config.per_server,
check_servers = function(callback) {
for(var i = 0; i < servers.length; i++) {
callback(i, servers[i]);
}
};
this.add_server = function(port) {
var server = {
port: port,
load: 0,
process: cp.fork(__dirname + '/../server_instance.js', [], {
env: {
port: port
}
})
};
server.process.on('message', function(message) {
server.load = message.load;
});
servers.push(server);
};
this.find_server = function() {
var min = Infinity,
port = false;
check_servers(function(index, details) {
if(details.load < min) {
min = details.load;
port = details.port;
}
});
return port;
};
现在如果我连续执行 controller.add_server()
40 次,它将正确启动 40 个服务器,但如果我这样做:
var start_port = 3185;
setInterval(function() {
var min = Infinity;
check_servers(function(index, details) {
if(details.load < min) {
min = details.load;
}
});
if(min > config.per_server) {
controller.add_server(start_port);
start_port++;
}
}, 5000);
我会随机地在第二、第三或第四个服务器创建时遇到地址已被使用的错误。
07.11.2017编辑 ----
如建议所述,我尝试了以下端口扫描/查找库:
- portfinder - portscanner - scan-ports 只有使用第一个库,我才能启动至少两个服务器,这是我使用的代码:
setInterval(function() {
var min = Infinity;
check_servers(function(index, details) {
if(details.load < min) {
min = details.load;
}
});
if(min > per_server) {
_self.add_server();
}
}, 5000);
var portfinder = require('portfinder');
portfinder.basePort = 3185;
this.add_server = function() {
portfinder.getPortPromise()
.then((port) => {
console.log('port found', port);
var server = {
port: port,
load: 0,
process: cp.fork(__dirname + '/../server_instance.js', [], {
env: {
port: port
}
})
};
server.process.on('message', function(message) {
server.load = message.load;
});
servers.push(server);
})
.catch((err) => {
console.log('error happened');
});
};
经过多次测试,看起来我可以启动2个服务器,然后随机地,在第三或第四次尝试时崩溃。很明显问题比端口查找更深入,这个库只是告诉我我已经知道的东西,我知道哪些端口是开放的,并在脚本尝试使用手动
netstat -anp | grep PORT
命令启动服务器之前进行了双重检查。因此,很明显问题不在于查找打开的端口,从结果来看,似乎node正在尝试从单个命令中多次启动服务器。
跟进编辑 ----
添加server_instance.js代码:
var io = require('socket.io')(process.env.port),
connections_current = 0,
connections_made = 0,
connections_dropped = 0;
io.on('connection', function(socket) {
connections_current++;
connections_made++;
// ... service logic here, not relevant (like query db, send data to users etc)
socket.on('disconnect', function() {
connections_current--;
connections_dropped++;
});
});
setInterval(function() {
process.send({
load: connections_current
});
}, 5000);
2017年08月11日编辑 ----
我测试了许多解决方案来解决这个问题,我观察到了这种情况:
在Mac OS X上的本地测试中,我可以生成最多3000个连接到服务器。错误从未发生过,节点有
1个进程
和6个线程
用于路由文件。使用3000个连接,我甚至可以生成200个服务器而没有任何问题。在Linux Debian上的服务器测试中,我生成了2百万个连接到服务器。当我连接所有人时,错误总是发生在第3或第4个服务器实例上,节点有
6个进程
和每个进程的
用于路由文件。10个线程
这显然是问题的根源,我拥有的容量越大,节点产生的进程就越多,尝试启动新服务器时它会更快地重叠。
setInterval()
代码会无限运行,启动越来越多的服务器,直到耗尽服务器端资源。 - jfriend00