667

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

那么它如何针对多核 CPU 和多 CPU 服务器进行扩展呢?毕竟,尽可能快的单线程服务器是很棒的,但是对于高负载,我想使用几个 CPU。使应用程序更快也是如此 - 今天的方式似乎是使用多个 CPU 并并行化任务。

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

4

17 回答 17

742

[这篇文章是 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“集群”模块不同。

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

工作人员将竞争接受新的连接,负载最少的进程最有可能获胜。它工作得很好,并且可以在多核机器上很好地扩展吞吐量。

如果您有足够的负载来处理多个内核,那么您还需要做更多的事情:

  1. 在NginxApache之类的网络代理后面运行您的 Node.js 服务- 可以进行连接限制(除非您希望过载条件完全关闭盒子)、重写 URL、提供静态内容和代理其他子服务。

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

  3. 设置日志收集/监控


PS:Aaron 和 Christopher 在另一篇文章的评论中进行了讨论(在撰写本文时,它是最重要的帖子)。对此有几点评论:

  • 共享套接字模型非常方便允许多个进程侦听单个端口并竞争接受新连接。从概念上讲,您可以考虑预先分叉的 Apache 这样做,但需要注意的是每个进程将只接受一个连接然后死掉。Apache 的效率损失在于分叉新进程的开销,与套接字操作无关。
  • 对于 Node.js,让 N 个 worker 在一个 socket 上竞争是一个非常合理的解决方案。另一种方法是设置一个像 Nginx 这样的机上前端,并将代理流量分配给各个工作人员,在工作人员之间交替分配新的连接。这两种解决方案具有非常相似的性能特征。而且,正如我上面提到的,无论如何,您可能希望 Nginx(或替代方案)在您的节点服务前面,这里的选择实际上是:

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

对比

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

可以说,单独的端口设置有一些好处(可能减少进程之间的耦合,有更复杂的负载平衡决策等),但设置起来肯定需要更多的工作,并且内置的集群模块很低-适用于大多数人的复杂性替代方案。

于 2011-12-31T02:48:09.290 回答
47

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

于 2010-03-10T05:47:51.537 回答
31

Ryan Dahl在去年夏天在 Google 的技术演讲中回答了这个问题。套用一句话,“只需运行多个节点进程并使用合理的方式让它们进行通信。例如 sendmsg() 风格的 IPC 或传统的 RPC”。

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

更新 - 2011 年 10 月 11日:节点社区的共识似乎是集群现在是管理每台机器多个节点实例的首选模块。 永远也值得一看。

于 2010-12-09T12:46:40.273 回答
25

您可以使用集群模块。检查这个

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);
}
于 2014-04-27T20:23:08.653 回答
16

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.
}

查看这篇文章以获得完整的教程

于 2015-10-02T14:53:26.630 回答
13

如上所述,集群将在所有内核上扩展和负载平衡您的应用程序。

添加类似的东西

cluster.on('exit', function () {
  cluster.fork();
});

将重新启动任何失败的工人。

这些天,很多人也更喜欢PM2,它为您处理集群并提供一些很酷的监控功能

然后,在运行集群的多台机器前添加 Nginx 或 HAProxy,您将拥有多级故障转移和更高的负载能力。

于 2015-02-05T15:52:28.120 回答
13

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

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

于 2010-07-20T10:04:45.197 回答
11

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

npm i -g pm2
pm2 start app.js -i max
于 2016-11-21T22:36:12.247 回答
8

未来版本的 node 将允许您分叉一个进程并将消息传递给它,Ryan 表示他希望找到一些方法来共享文件处理程序,因此它不会是一个直接的 Web Worker 实现。

目前还没有一个简单的解决方案,但它还为时过早,node 是我见过的发展最快的开源项目之一,所以期待在不久的将来会有一些很棒的东西。

于 2010-03-13T18:51:05.970 回答
7

Spark2 基于现在不再维护的 Spark。Cluster是它的继任者,它有一些很酷的特性,比如每个 CPU 核心生成一个工作进程和重生死掉的工作进程。

于 2011-03-08T13:02:49.237 回答
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();
}

于 2018-09-20T12:41:34.893 回答
5

The new kid on the block here is LearnBoost's "Up".

It provides "Zero-downtime reloads" and additionally creates multiple workers (by default the number of CPUs, but it is configurable) to provide the best of all Worlds.

It is new, but seems to be pretty stable, and I'm using it happily in one of my current projects.

于 2012-02-03T19:14:11.967 回答
5

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

于 2010-05-24T17:23:40.310 回答
1

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

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

pm2 start app.js -i 2 --wait-ready

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

process.send('ready');

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

而如果你使用 nodejs 的集群,当你重新启动并等待服务器准备好时会有停机时间。

于 2021-01-29T09:09:46.623 回答
1

我为所有可用的 CPU 内核搜索了 Clusterize an app,并在这里找到了我自己。我在哪里找到这个关键字是 Pm2 命令

pm2 示例

这是我发现的

  • 将应用程序集群到所有可用的 CPU 内核:

    $ pm2 开始 -i 最大值

如果你需要安装 pm2 使用这些命令

npm install -g pm2

yan add -g pm2

或者

在此处使用此链接

于 2021-11-07T05:51:13.960 回答
0

可以使用纯 TCP 负载均衡器 (HAProxy) 将 NodeJS 扩展到多个盒子,这些盒子在每个运行一个 NodeJS 进程的多个盒子前面。

如果您在所有实例之间共享一些常识,则可以使用中央 Redis 存储或类似存储,然后可以从所有流程实例(例如,从所有盒子)访问它

于 2011-11-10T15:14:31.607 回答
0

也可以将 Web 服务设计为几个独立的服务器,监听 unix 套接字,这样您就可以将数据处理等功能推送到单独的进程中。

这类似于大多数脚本/数据库 Web 服务器架构,其中 cgi 进程处理业务逻辑,然后通过 unix 套接字将数据推送和拉取到数据库。

不同之处在于数据处理被编写为侦听端口的节点网络服务器。

它更复杂,但最终它必须去多核开发。为每个 Web 请求使用多个组件的多进程架构。

于 2010-04-12T00:39:13.363 回答