多核机器上的Node.js

zah*_*pov 582 javascript node.js node-cluster

Node.js看起来很有趣,我必须错过一些东西 - 不是Node.js只调整为在单个进程和线程上运行吗?

那么它如何扩展多核CPU和多CPU服务器?毕竟,尽可能快速地制作单线程服务器,但是对于高负载我想要使用多个CPU.同样可以使应用程序更快 - 似乎今天的方式是使用多个CPU并并行化任务.

Node.js如何适应这张图片?它的想法是以某种方式分发多个实例或什么?

Dav*_*son 680

[ 这篇文章是截至2012-09-02的最新消息(比上面的更新).]

Node.js绝对可以在多核机器上进行扩展.

是的,Node.js是每个进程一个线程.这是一个非常慎重的设计决策,无需处理锁定语义.如果您不同意这一点,您可能还没有意识到调试多线程代码是多么的难以理解.有关Node.js流程模型的更深入解释以及为什么它以这种方式工作(以及为什么它永远不会支持多个线程),请阅读我的其他帖子.

那么如何利用我的16核心盒?

两种方式:

  • 对于像图像编码这样的大型计算任务,Node.js可以启动子进程或向其他工作进程发送消息.在这个设计中,你有一个线程来管理事件流和N个进程执行繁重的计算任务并咀嚼其他15个CPU.
  • 为了在Web服务上扩展吞吐量,您应该在一个盒子上运行多个Node.js服务器,每个核心一个,并在它们之间分割请求流量.这提供了出色的CPU亲和力,并且可以随着核心数量几乎线性地扩展吞吐量.

扩展Web服务的吞吐量

由于v6.0.X Node.js 直接包含了集群模块,因此可以轻松设置可以在单个端口上侦听的多个节点工作程序.请注意,这与通过npm提供的较旧的learnboost"cluster"模块不同.

if (cluster.isMaster) {
  // Fork workers.
  for (var i = 0; i < numCPUs; i++) {
    cluster.fork();
  }
} else {
  http.Server(function(req, res) { ... }).listen(8000);
}
Run Code Online (Sandbox Code Playgroud)

工人将竞争接受新的联系,最少负担的过程最有可能获胜.它运行良好,可以在多核盒上很好地扩大吞吐量.

如果你有足够的负载来关心多个核心,那么你也想要做更多的事情:

  1. 在像NginxApache这样的Web代理后面运行Node.js服务- 可以进行连接限制(除非您希望过载条件完全关闭框),重写URL,提供静态内容以及代理其他子服务.

  2. 定期回收您的工作进程.对于长时间运行的进程,即使很小的内存泄漏最终也会增加.

  3. 设置日志收集/监视


PS:Aaron和Christopher在另一篇文章的评论中进行了讨论(截至本文撰写时,它是最高职位).对此有一些评论:

  • 共享套接字模型非常便于允许多个进程侦听单个端口并竞争接受新连接.从概念上讲,你可以想到preforked Apache这样做的重要警告是每个进程只接受一个连接然后死掉.Apache的效率损失是分支新进程的开销,与套接字操作无关.
  • 对于Node.js,让N个工作者在单个套接字上竞争是一个非常合理的解决方案.另一种方法是建立一个像Nginx这样的机上前端,并为每个工作人员提供代理流量,在工作人员之间交替分配新连接.这两种解决方案具有非常相似的性能特征 因为,正如我上面提到的,你可能想要让Nginx(或替代方案)面向你的节点服务,这里的选择实际上是:

共享端口: nginx (port 80) --> Node_workers x N (sharing port 3000 w/ Cluster)

VS

个人港口: nginx (port 80) --> {Node_worker (port 3000), Node_worker (port 3001), Node_worker (port 3002), Node_worker (port 3003) ...}

对于各个端口设置可能有一些好处(可能在进程之间具有较少的耦合,具有更复杂的负载平衡决策等),但是设置肯定更多工作并且内置集群模块是低的 - 适用于大多数人的复杂替代品.

  • 你应该发一个问题!(我将把这个评论复制为你的第一个答案).你想要做的事实上真的很简单.你真的不需要"集群",你只需要运行两个不同的节点服务.两个脚本,两个进程,两个端口.例如,你可以让serviceA监听3000并且serviceB监听3001.这些服务中的每一个都可以使用"集群"来拥有1个以上的工作人员并定期回收它们等等.然后你可以配置Nginx来监听端口80并转发到基于传入的"主机"标头和/或URL路径的正确服务. (6认同)
  • 你能提供关于在一个盒子上运行不同的基于 nodejs 的服务的任何建议吗?例如,假设我有 1 个服务器,想在 CpuCore1 上运行 myservice1.js,在 CpuCore2 上运行 myservice2.js。我可以为此使用集群吗?还是只对创建克隆服务有用? (2认同)

Cha*_*kar 46

一种方法是在服务器上运行node.js的多个实例,然后在它们前面放置一个负载均衡器(最好是非阻塞的,如nginx).

  • node.js和nginx一样快,你可以把node.js负载均衡器放在你的node.js服务器前面,如果你想要的话:) (33认同)
  • ryan明确表示不要这样做,直到节点更稳定.最好的方法是在节点前面运行nginx. (26认同)
  • 同样,nginx不完全支持HTTP 1.1,因此WebSockets之类的东西无法代理. (4认同)
  • 对于节点前面的nginx,它不会解决某些问题,例如你是否有内存中的队列.2个节点实例将无法访问彼此的队列. (2认同)
  • @mikeal,resopollution - 我强烈关注Nginx方面.我多次硬崩溃Node.js(没有堆栈跟踪,只是死掉).我从来没有撞过Nginx.开箱即用的Nginx配置了各种理智的节流阀.默认情况下,Node.js将继续接受新连接而不是服务现有连接,直到该框关闭...是的,整个框; 我通过压力测试节点在CentOS5盒子上崩溃内核(现在真的不应该发生).我来了一点,我看到了Node的光明前景,可能包括专用的LB型角色.还没有. (2认同)

bro*_*ofa 30

Ryan Dahl 去年夏天他在Google发表的技术讲话中回答了这个问题.换言之,"只需运行多个节点进程并使用合理的东西来允许它们进行通信.例如sendmsg() - 样式IPC或传统的RPC".

如果您想立即弄脏手,请查看spark2 Forever模块.它使得生成多个节点进程变得非常简单.它处理设置端口共享,因此它们每个都可以接受到同一端口的连接,并且如果要确保进程在其停止时重新启动,也会自动重新生成.

更新 - 10/11/11:节点社区中的共识似乎是Cluster现在是每台机器管理多个节点实例的首选模块. 永远值得一看.

  • Forever和Cluster做了很多不同的事情.你甚至可以同时使用它们.Forever在死亡时重启一个进程.集群管理多个工作者.您将使用Forever来管理主进程... (8认同)
  • 另外,learnboost模块很大程度上取决于烘焙到Node v0.6.x中的Cluster版本(警告:API表面确实不同) (4认同)

小智 19

您可以使用群集模块.检查一下.

var cluster = require('cluster');
var http = require('http');
var numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
    // Fork workers.
    for (var i = 0; i < numCPUs; i++) {
        cluster.fork();
    }

    cluster.on('exit', function(worker, code, signal) {
        console.log('worker ' + worker.process.pid + ' died');
    });
} else {
    // Workers can share any TCP connection
    // In this case its a HTTP server
    http.createServer(function(req, res) {
        res.writeHead(200);
        res.end("hello world\n");
    }).listen(8000);
}
Run Code Online (Sandbox Code Playgroud)


Cyb*_*nic 13

多节点利用您可能拥有的所有核心.
看看http://github.com/kriszyp/multi-node.

对于更简单的需求,您可以在不同的端口号上启动多个节点副本,并在其前面放置负载均衡器.


Wil*_*ern 10

如上所述,Cluster将跨所有核心扩展和负载均衡您的应用.

添加类似的东西

cluster.on('exit', function () {
  cluster.fork();
});
Run Code Online (Sandbox Code Playgroud)

将重启任何失败的工人.

如今,很多人也更喜欢PM2,它可以为您处理集群,并提供一些很酷的监控功能.

然后,在运行集群的多台计算机前添加Nginx或HAProxy,您可以实现多级故障转移和更高的负载容量.

  • PM2非常适合生产使用。监视工具帮助我解决了应用程序的内存问题。 (2认同)

Tou*_*umi 10

Node Js支持集群,以充分利用您的cpu.如果您没有使用群集运行它,那么您可能正在浪费您的硬件功能.

Node.js中的群集允许您创建可以共享相同服务器端口的单独进程.例如,如果我们在端口3000上运行一个HTTP服务器,则它是一个服务器在单核处理器上的单线程上运行.

下面显示的代码允许您对应用程序进行分组.此代码是Node.js代表的官方代码.

var cluster = require('cluster');
var numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
    // Fork workers.
    for (var i = 0; i < numCPUs; i++) {
        cluster.fork();
    }

    Object.keys(cluster.workers).forEach(function(id) {
        console.log("I am running with ID : " + cluster.workers[id].process.pid);
    });

    cluster.on('exit', function(worker, code, signal) {
        console.log('worker ' + worker.process.pid + ' died');
    });
} else {

    //Do further processing.
}
Run Code Online (Sandbox Code Playgroud)

查看本文以获取完整教程


Ali*_*ter 10

集群模块允许你利用你的机器的所有核心。事实上,您只需使用 2 个命令即可利用这一点,而无需使用非常流行的流程管理器pm2 修改您的代码。

npm i -g pm2
pm2 start app.js -i max
Run Code Online (Sandbox Code Playgroud)


mik*_*eal 7

节点的未来版本将允许您创建一个进程,并传递消息给它和瑞安曾表示,他希望找到某种方式也分享文件处理程序,所以它不会是一个简单的Web工作落实.

目前还没有一个简单的解决方案,但它仍然很早,节点是我见过的最快速移动的开源项目之一,所以期待在不久的将来有一些很棒的东西.


小智 7

Spark2基于Spark,现在不再维护.Cluster是它的继承者,它有一些很酷的功能,比如每个CPU核心产生一个工作进程并重新生成死亡工人.


Ole*_*leb 7

您可以通过将cluster模块与os模块结合使用来在多个内核上运行您的 node.js 应用程序,该模块可用于检测您拥有的 CPU 数量。

例如,假设您有一个server在后端运行简单 http 服务器的模块,并且您希望为多个 CPU 运行它:

// Dependencies.
const server = require('./lib/server'); // This is our custom server module.
const cluster = require('cluster');
const os = require('os');

 // If we're on the master thread start the forks.
if (cluster.isMaster) {
  // Fork the process.
  for (let i = 0; i < os.cpus().length; i++) {
    cluster.fork();
  }
} else {
  // If we're not on the master thread start the server.
  server.init();
}
Run Code Online (Sandbox Code Playgroud)


Som*_*ial 6

重要区别 - 滚动重启

我必须添加使用节点的集群模式构建与 PM2 集群模式等流程管理器之间的一个重要区别。

PM2 允许您在跑步时零停机时间重新加载。

pm2 start app.js -i 2 --wait-ready
Run Code Online (Sandbox Code Playgroud)

在您的代码中添加以下内容

process.send('ready');
Run Code Online (Sandbox Code Playgroud)

当您pm2 reload app在代码更新后调用时,PM2 将重新加载应用程序的第一个实例,等待“就绪”调用,然后继续重新加载下一个实例,确保您始终有一个活跃的应用程序来响应请求。

而如果您使用 Nodejs 的集群,当您重新启动并等待服务器准备就绪时,将会出现停机时间,因为应用程序只有一个实例,并且您要一起重新启动所有核心。


小智 5

我正在使用Node worker以一种简单的方式从我的主进程运行进程.当我们等待正式的出路时,似乎工作得很好.


小智 5

这里的新孩子是LearnBoost的"Up".

它提供"零停机重新加载",并另外创建多个工作程序(默认情况下,CPU的数量,但它是可配置的),以提供所有世界中最好的.

它是新的,但似乎非常稳定,我在我目前的一个项目中愉快地使用它.