javascript - Node.js 集群架构 : how to scale master worker

标签 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 个 worker,在 master.js 中有 1 个 master。 Master 和 worker 共享公共(public)模块,而 master 有一个核心模块加载核心服务并在 PORT=3001 上公开一个 api,worker 在 PORT=3000 上加载其他 api >,其中已绑定(bind) Docker 容器。虽然 Worker 上的路由代理会将请求转发给 Master 以便为核心模块提供服务,但其他请求直接在 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 上的 express web 应用程序中提供静态文件、模板(如 pig/swig),这意味着我为 web 运行静态路由生成的每个工作实例上的应用程序。就内存占用而言,我不确定这是否是最佳方法。

3) 其他聚类方法。我已经询问过将此架构迁移到 PM2,尽管它看起来很有希望,但我不确定它是否是最佳选择 - 参见 here了解更多详情。

最佳答案

主人应该只关心启动工作人员并正确关闭他们/注意来自主机的信号并做出相应的响应。根据我的经验,我遇到过一些棘手的错误,因为我在 master 上公开了一个本应在 worker 上公开的 API。

如果您打算切换到 PM2,PM2 将处理您的 master,您无论如何都需要将该代码移至 worker(或者至少过去是这样)

关于您的问题;

  1. 如果您需要覆盖循环法或自定义它,我认为您的目标是将相同的客户端流量路由到相同的工作人员,也称为粘性 session 。 There are ways to do so但也有限制;如果你在 Node 前使用像 nginx 或 haproxy 这样的反向代理(你应该这样做)并且还希望套接字按预期工作(并且在游戏中有 Docker),你不能真正分散工作人员因为你看到的 IP (您将在其上计算粘性 session ID)将始终是您的代理或 docker 主机之一(即使使用 x-forwarded-for header ),这首先违背了集群的目的。 -> 我的解决方案是在新端口(例如 3001、3002 ... 300N)上启动每个工作人员,并让 nginx 处理粘性 session 处理
  2. 这不是问题,但并不理想 - 是的,内存会略微增加,因为每个 worker 都会加载路由和模块。但是 nginx 在处理静态文件(以及使用许多 http-headers 处理它的缓存)方面比 node 快得多。所以你应该依靠 nginx 服务静态并为动态请求保留 Node (比如/api/login 等)
  3. PM2 是一个很好的解决方案,它具有许多高级功能,例如报告统计信息和处理零停机部署,但也需要付费,具体取决于您要使用的功能

关于javascript - Node.js 集群架构 : how to scale master worker,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52889568/

相关文章:

javascript - 在警报页面上单击“确定”后重新加载页面

javascript - ionic 2 : can't scroll all the content of the page

node.js - Passport 抛出 user.authenticate 不是一个函数

docker - 将文件从ftp复制到docker容器

javascript - 用于 Bootstrap 网站的 jquery 轮播,在滚动时覆盖我的页面

javascript - 如何在移动和桌面设备上缩放 Canvas

node.js - intellij idea 中的多个 ECMA-Script 版本

node.js - 代理的 websocket 连接立即关闭

curl - 如何在docker中使用文件系统创建卷?

javascript - MongoDB init-script 未使用 docker-compose 启动