Node.js群集体系结构:如何缩放主辅助角色



我构建了一个具有主/工作线程配置的 Node.js 内置集群架构。该应用程序使用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,一个工作线程在绑定 Docker 容器的PORT=3000上加载其他 API。虽然工作线程上的路由代理会将请求转发到主服务器以便为核心模块的请求提供服务,但其他请求直接在 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 连接使用轮询方法来处理请求 - 请参阅此处,其中使用 child_process.fork(( 生成工作进程。我不知道我是否可以自定义此方法以分发传入连接。

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

3(其他聚类方法。我已经询问过将此架构迁移到PM2,尽管它似乎很有希望,但我不确定这是最佳选择 - 有关更多详细信息,请参阅此处。

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

如果您打算切换到 PM2,PM2 将处理您的主节点,无论如何您都需要将该代码移动到工作线程(或者至少以前是这种情况(

关于您的问题;

  1. 如果您需要覆盖轮询或自定义它,我认为您的目标是将相同的客户端流量路由到同一个工作线程,也就是粘性会话。有办法这样做,但也有局限性;如果您在节点前面使用像 nginx 或 haproxy 这样的反向代理(您应该这样做(,并且还希望套接字按预期工作(并在游戏中使用 Docker(,那么您不能真正在 worker 上扇出,因为您看到的 IP(您将在其上计算粘性会话 ID(将始终是您的代理或您的 docker 主机之一(即使带有 x-forwarded-for 标头(, 这首先违背了聚类的目的。 -> 我的解决方案是在新端口上启动每个工作线程(例如 3001、3002 ...300N(并让nginx处理粘性会话处理
  2. 这不是问题,但并不理想 - 是的,内存会略有增加,因为每个工作线程都会加载路由和模块。但是nginx在处理静态文件(以及使用许多http-headers处理它的缓存(方面比node快得多。所以你应该依靠nginx服务静态和保持节点的动态请求(如/api/login等(。
  3. PM2 是一个很好的解决方案,具有许多高级功能,例如报告统计数据和处理零停机时间部署,但也要花钱,具体取决于您要使用的功能

最新更新