node.js只强制一个线程执行代码

Mev*_*via 7 javascript multithreading node.js socket.io

当我启动我的应用程序时node app.js,运行的进程只有一个线程.无论运行的时间越长,为该进程制作的线程越多.问题是,当我想执行这样的特定代码时:

var io = require('socket.io')(process.env.PORT);
Run Code Online (Sandbox Code Playgroud)

它失败是因为信号是从多个线程发送的,因此代码未成功执行.

简单测试,如果这样做:

var io = require('socket.io')(9001);
var io = require('socket.io')(9002);
var io = require('socket.io')(9003);
var io = require('socket.io')(9004);
Run Code Online (Sandbox Code Playgroud)

它工作正常,但这段代码:

var cPort = 9001;
setInterval(function() {
    var io = require('socket.io')(cPort);
    cPort++;
}, 1000 * 60 * 2); // 1 sec * 60 seconds * 2 = 2 minutes interval
Run Code Online (Sandbox Code Playgroud)

不会被执行,因为2分钟后节点将有许多线程,他们都试图执行代码 - 因此你会看到error: address in use.

因此,尽管运行相同文件的多线程进程,我怎么能强制节点只执行一次这个代码?

06.11.2017编辑----

澄清问题:

我在问题中的意思是,我没有资源问题,如果我一次启动所有服务器(例如40台服务器),它们都已成功启动并无限期地工作.如果我只启动一个服务器,然后运行在需要时自动启动更多的代码,则会出现问题.在那一点上我总是看到address in use错误,显然地址在代码执行的时刻没有被使用.目前,我必须在周末手动启动更多服务器,因为有更多人在一周的其他日子使用服务和更少的服务器,我想创建基于人口启动和关闭服务器的自动化系统.

这是服务器启动的代码:

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;
};
Run Code Online (Sandbox Code Playgroud)

现在,如果我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);
Run Code Online (Sandbox Code Playgroud)

我在第二次,第三次或第四次服务器创建时得到随机错误,该地址已被使用.

07.11.2017编辑----

正如建议我尝试使用以下库进行端口扫描/查找:

只使用第一个我能够启动至少2个服务器,这是我使用的代码:

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');
        });
};
Run Code Online (Sandbox Code Playgroud)

经过多次测试后,看起来我可以启动2台服务器然后随机,在第三次或第四次尝试时崩溃.很明显,问题更深入,然后端口查找,这个库只告诉我我已经知道的东西,我知道打开了什么端口,并且我仔细检查脚本之前是否会尝试使用手动netstat -anp | grep PORT命令启动服务器.

所以很清楚,问题不在于找到打开的端口,从结果的角度来看,似乎节点试图从单个命令多次启动服务器.

跟进编辑----

添加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);
Run Code Online (Sandbox Code Playgroud)

08.11.2017编辑----

我正在测试许多解决问题的解决方案,我观察到了这种情况:

  • 在mac osx上进行本地测试,我可以在服务器上生成最多3000个连接.错误永远不会发生,节点有1 process6 threads路由器文件.通过3000个连接,我甚至可以生成200台服务器而没有任何问题

  • 在linux debian上的服务器测试,我生成2毫升到服务器的连接.当我连接所有人节点6 processes10 threads for every process路由器文件时,错误总是发生在第3或第4服务器实例上.

这显然是问题的根源,我拥有的容量越多,节点产生的进程就越多,并且在尝试启动新服务器时它会更快地重叠.

Jeh*_*lio 1

最好的解决方案是在主进程中生成端口号,然后将它们传递给工作进程,以便它们不相交。

您还可以检查端口是否正在使用,并使用 npm 模块(如test-port-provider )获取可用端口。