Node.js集群体系结构:如何扩展主工作者

时间:2018-10-19 09:27:48

标签: javascript node.js docker node-cluster

我已经使用主/工作人员配置构建了Node.js内置cluster架构。该应用程序正在使用express来提供api和静态文件,并与Docker一起部署:

[D O C K E R: 8080] --- N ---> [W O R K E R: 3001 ]  --- 1 ---> [M A S T E R: 3000]

我在Worker.js中有N个工人,在master.js中有1个主人。主服务器和工作服务器共享通用模块,而主服务器有一个核心模块,该模块可以加载核心服务并在PORT=3001上公开一个api,而工作服务器则在PORT=3000上将其他api加载到已绑定了Docker容器的地方。虽然工作服务器上的路由代理会将请求转发到主服务器,以便将请求服务到核心模块,但其他请求则直接在3000上作为服务器。

启动脚本看起来像

'use strict';
(function() {

/// node clustering
const cluster = require('cluster');
const numCPUs = require('os').cpus().length;

if (cluster.isMaster) { // master node
    var masterConfig=require('./config/masterconfig.json');

    // Fork workers.
    var maxCPUs = process.env.WORKER_NUM || masterConfig.cluster.worker.num;
    maxCPUs=(maxCPUs>numCPUs)?numCPUs:maxCPUs;

    for (let i = 0; i < maxCPUs; i++) {
        const worker=cluster.fork();
    }

    var MasterNode=require('./lib/master');
    var master= new MasterNode(masterConfig);
    master.start()
    .then(done=> {
        console.log(`Master ${process.pid} running on ${masterConfig.pubsub.node}`);
    })
    .catch(error=> { // cannot recover from master error
        console.error(`Master ${process.pid} error`,error.stack);
        process.exit(1);
    });
}
else if (cluster.isWorker) { // worker node
    var workerConfig=require('./config/workerconfig.json');
    var WorkerNode=require('./lib/worker');
    var worker= new WorkerNode(workerConfig);
    worker.start()
    .then(done=> {
        console.log(`Worker ${process.pid} running on ${workerConfig.pubsub.node}`);
    })
    .catch(error=> { // worker error is recoverable
        console.error(`Worker ${process.pid} error`,error.stack);
    });
}

}).call(this);

我有以下问题。

1)默认情况下,cluster模块共享带下划线的HTTP连接,使用round-robin方法处理请求-请参见here,其中使用child_process.fork()生成工作进程。我不知道是否可以自定义此方法来分配传入的连接。

2)到目前为止,我在PORT=3000的每个Worker上的快速Web应用程序中提供静态文件,模板(例如pig / swig),这意味着我在每个worker实例上为该Web应用程序运行了静态路由产生。就内存占用而言,我不确定这是否是最佳方法。

3)其他聚类方法。我曾问过有关将这种体系结构迁移到PM2的问题,尽管它似乎很有前途,但我不确定它是否是最佳选择-有关更多详细信息,请参见here

1 个答案:

答案 0 :(得分:3)

主机只应关心启动工作程序并正确关闭它们/当心来自主机的信号并作出相应响应。根据我的经验,我遇到了一些棘手的错误,因为我在主服务器上公开了应该由工作人员使用的API。

如果您打算切换到PM2,则PM2将处理您的主服务器,并且无论如何(或者至少以前是这种情况),您都需要将该代码移交给工作人员

关于您的问题;

  1. 如果您需要覆盖循环或对其进行自定义,我认为您的目标是将相同的客户流量路由到相同的工作人员,即粘性会话。 There are ways to do so,但有局限性;如果您在节点前使用反向代理(例如nginx或haproxy)(应该这样做),并且还希望套接字按预期方式工作(并且在游戏中安装了Docker),那么您就无法真正分散工作人员,因为您看到的IP (您将在其上计算粘性会话ID)(永远是您的代理服务器)或Docker主机(即使使用x-forwarded-for标头)也是如此,这首先破坏了群集的目的。 ->我的解决方案是在每个新端口(例如3001、3002 ... 300N)上启动每个工作线程,然后让Nginx处理粘性会话处理
  2. 这不是问题,但也不是理想的-是的,由于每个工作程序都加载了路由和模块,因此内存将略有增加。但是,nginx在处理静态文件(以及使用许多http标头处理缓存)方面比节点要快得多。因此,您应该依靠nginx提供静态服务,并为动态请求(例如/ api / login等)保留节点
  3. PM2是一个很好的解决方案,它具有许多高级功能,例如报告统计信息和处理零停机时间部署,但根据要使用的功能,也会花费很多钱