多核计算机上的节点.js

2022-08-29 22:36:16

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

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

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


答案 1

[这篇文章是最新的 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);
}

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

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

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

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

  3. 设置日志收集/监控


PS:在另一篇文章的评论中有亚伦和克里斯托弗之间的讨论(在撰写本文时,这是头条新闻)。对此有几点评论:

  • 共享套接字模型非常方便,允许多个进程在单个端口上侦听并竞争接受新连接。从概念上讲,你可以想到预分叉的Apache这样做,但有一个重要的警告,即每个进程只接受一个连接,然后死亡。Apache的效率损失在于分叉新进程的开销,与套接字操作无关。
  • 对于 Node.js来说,让 N 个 worker 在单个套接字上竞争是一个非常合理的解决方案。另一种方法是设置一个像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) ...}

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


答案 2

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