【问题标题】:What is Node.js cluster best practice?什么是 Node.js 集群最佳实践?
【发布时间】:2019-01-25 16:41:08
【问题描述】:

在 fork worker 之前还是之后编写我们的服务器逻辑更好?

我将在下面举两个例子来说明清楚。

示例 #1:

const express = require("express");
const cluster = require('cluster');
const app = express();

app.get("/path", somehandler);

if (cluster.Master)
  // forking workers..
else
  app.listen(8000);

或示例 #2:

const cluster = require('cluster');

if (cluster.Master)
  // forking workers..
else {
  const express = require("express");
  const app = express();

  app.get("/path", somehandler);

  app.listen(8000);
}

有什么区别?

【问题讨论】:

    标签: javascript node.js server


    【解决方案1】:

    没有区别。因为当您调用 cluster.fork() 时,它会在 same entry file 上调用 child_process.fork 并保留子进程处理程序以进行进程间通信。

    读取在cluster's master模块后面的行中定义的以下方法:1671025152


    让我们回到你的代码:

    1. 在示例 #1 中,它分配变量,为主进程和子进程创建应用实例,然后检查进程是否是主进程。

    2. 在示例 #2 中,它会检查进程是否为 master,如果没有,它会分配 var,创建应用实例并在端口上为子工作者绑定侦听器。


    其实它会在 clild 进程中做同样的操作:

    1. 分配变量

    2. 创建应用实例

    3. 开始监听


    我自己使用集群的最佳实践有 2 个步骤:

    第 1 步 - 在单独的模块中使用自定义集群包装器并在应用程序调用中进行包装:

    cluster.js文件:

    'use strict';
    
    module.exports = (callable) => {
      const
        cluster = require('cluster'),
        numCpu = require('os').cpus().length;
    
      const handleDeath = (deadWorker) {
        console.log('worker ' + deadWorker.process.pid + ' dead');
    
        const worker = cluster.fork();
        console.log('re-spawning worker ' + worker.process.pid);
      }
      
      process.on('uncaughtException',
        (err) => {
          console.error('uncaughtException:', err.message);
          console.error(err.stack);
        });
    
      cluster.on('exit', handleDeath);
      
      // no need for clustering if there is just 1 cpu
      if (numCpu === 1 || !cluster.isMaster) {
        return callable();
      }
      
      // saving 1 cpu for master process (1 M + N instances) 
      // or create 2 instances since 1 M + 1 Instance 
      // is ineffective when respawning instance
      // better to have 1 M + 2 instances if cpu count 2
      const instances = numCpu > 2 ? numCpu - 1 : numCpu; 
    
      console.log('Starting', instances, 'instances');
      for (let i = 0; i < instances; i++, cluster.fork());
    };
    

    保持app.js 像这样简单以实现模块化和可测试性(阅读supertest):

    'use strict';
    
    const express = require("express");
    const app = express();
    
    app.get("/path", somehandler);
    
    module.exports = app;
    

    在某个端口服务应用程序必须由不同的模块处理,所以server.js 看起来像这样:

    'use strict';
    
    const start = require('./cluster');
    
    start(() => {
      
      const http = require('http');
      const app = require('./app');
    
    
      const listenHost = process.env.HOST || '127.0.0.1';
      const listenPort = process.env.PORT || 8080;
      const httpServer = http.createServer(app);
    
      httpServer.listen(listenPort, listenHost,
          () => console.log('App listening at http://'+listenHost+':'+listenPort));
    });
    

    您可以在scripts 部分添加package.json 这样的行:

    "scripts": {
      "start": "node server.js",
      "watch": "nodemon server.js",
      ...
    }
    

    使用以下命令运行应用程序:

    node server.js, nodemon server.js

    npm start, npm run watch



    第 2 步 - 需要容器化时:

    保持Step 1中的代码结构并使用docker

    Cluster 模块将获取容器 orkestrator 提供的 cpu 资源

    此外,您还可以使用 docker swarmkubernetesdc/os 等按需扩展 docker 实例。

    Dockerfile

    FROM node:alpine
    
    ENV PORT=8080
    EXPOSE $PORT
    
    ADD ./ /app
    WORKDIR /app
    
    RUN apk update && apk upgrade && \
        apk add --no-cache bash git openssh
    
    RUN npm i
    CMD ["npm", "start"]
    

    【讨论】:

    • 如果有人投反对票,请指出我在回答中做错了什么。
    • 感谢您的快速回复,但是内存呢?我知道每个工人都有独立的内存,所以如果我在分叉后实例化应用程序和其他变量会消耗更多内存吗?如果我不这样做,这些变量会在工人之间共享吗?
    • each worker has independant memory - 是的,因为child_process.forkif i instantiate the app and other variables after forking will that consume more memory? - 当你调用 cluster.fork 它调用 child_process.fork 并再次运行相同的文件。根据您编写变量实例化的方式,它可能会在子进程或主进程上使用。所以更推荐示例#2。
    • instances 第一个代码块中的变量似乎没有在任何地方定义,它应该是 numCPUs 吗?
    • @G07cha 很好,所以我更新了我的代码
    猜你喜欢
    • 2015-10-04
    • 1970-01-01
    • 2016-09-08
    • 1970-01-01
    • 2023-03-14
    • 2011-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多