多核处理器上的 Node Js

Node Js On Multi-Core Processors

首先,我有一种直觉,这是一个非常完整的问题,但无论如何请听我说完。我在想,如果 Node Js 是一个单线程应用程序,那么我们可以 运行 在同一台机器上的不同端口上使用它的多个实例。假设我有一个 8 线程处理器,这是否意味着我可以拥有 8 个节点实例 运行ning 而不会影响性能。如果我安装了足够的 ram,然后我可以为这 8 个实例进行负载平衡

(此处为 V8 开发人员。)

是的,一般来说,运行在同一台机器上安装多个 Node 实例可以增加完成的工作总量。这类似于拥有多个 Chrome 选项卡,每个选项卡都可以执行一些单线程 JavaScript 工作。

也就是说,它很可能不像“8 线程处理器上的 8 个实例提供 8 倍的总吞吐量”那么简单,原因如下:

(1) 如果您实际上是指“8 线程”,即 4 核 + 超线程,那么从 4 到 8 个进程可能会带来 20-40% 的改进(取决于硬件架构和特定工作负载),而不是 2 倍.

(2) V8 确实使用了多个线程用于内部目的(主要是编译和垃圾收集),这就是为什么单个 Node 实例(取决于工作负载)可能会使用多个线程的原因之一 CPU core/thread.

(3) 另一个原因是,虽然 JavaScript 是单线程的,但 Node 所做的不仅仅是执行 JavaScript 的单个线程。后台发生的各种事情(准备就绪时会触发 JS 回调)也需要 CPU 资源。

(4) 最后,CPU 不一定是你的瓶颈。如果您的服务器性能受到限制,例如网络或磁盘,那么生成更多实例将无济于事;相反,它可能会使事情变得更糟。

长话短说:尝试并没有坏处。作为第一步,运行 一个实例上的典型工作负载,并查看当前系统负载(CPU、内存、网络、磁盘)。如果它们 all 有足够的闲置容量,尝试去两个实例,测量是否增加整体吞吐量,并再次检查系统负载。然后继续添加实例,直到您发现它不再有帮助为止。

除了 @jmrk 提供的出色答案外,我还想对您问题的 "different ports" 部分发表评论。

在多进程方面,nodejs 最棒的地方之一就是 Cluster Module。您可以 运行 1 个进程并分叉多次,并且 您可以让它们都监听同一个端口 。因此,例如,您不必使用 Nginx 管理所有端口。

如果您想部署到可能具有不同内核数的计算机集群,您可以通过将 OS Module 引入游戏来动态执行此操作。

const cluster = require('cluster')

if (cluster.isMaster) {
  // Creates the Forks
  process.title = 'my-node-app-master'
  const { length: numberOfProcs } = require('os').cpus()
  for (let i = 0; i < numberOfProcs; i++) {
    cluster.fork()
  }

  // and here you can fork again when one of the forks dies
  cluster.on('exit', (worker, code, signal) => {
    console.error(`worker ${worker.process.pid} died (${signal || code}). restarting it in a sec`)
    setTimeout(() => cluster.fork(), 1000)
  })
} else {
  // run your server
  const http = require('http')
  process.title = 'my-node-app-fork'

  http.Server((req, res) => {
    res.writeHead(200)
    res.end(`hello world from pid ${process.pid}\n`)
  }).listen(8000)
}

process.title 将有助于检查过程。我 运行 我机器上的那个代码 我得到了这个:

$ ps aux | grep node-app
daniel    8062  1.1  0.1 550008 31380 pts/1    Sl+  12:27   0:00 my-node-app-master
daniel    8069  0.5  0.1 549168 30476 pts/1    Sl+  12:27   0:00 my-node-app-fork
daniel    8070  0.3  0.1 549176 30644 pts/1    Sl+  12:27   0:00 my-node-app-fork
daniel    8077  0.5  0.1 549168 30376 pts/1    Sl+  12:27   0:00 my-node-app-fork
...
daniel    8157  0.3  0.1 549168 30668 pts/1    Sl+  12:27   0:00 my-node-app-fork
daniel    8194  0.0  0.0   9028  2468 pts/2    R+   12:28   0:00 grep --color=auto node-app

然后几个要求:

$ curl http://localhost:8000
hello world from pid 8069
$ curl http://localhost:8000
hello world from pid 8070
$ curl http://localhost:8000
hello world from pid 8077

并且当您终止其中一个子进程时

$ kill -9 8077

日志将显示

worker 8077 died (SIGKILL). restarting it in a sec

我知道它与你的主要问题没有直接关系,但它仍然相关,我认为可以很好地利用它。