多核处理器上的 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
我知道它与你的主要问题没有直接关系,但它仍然相关,我认为可以很好地利用它。
首先,我有一种直觉,这是一个非常完整的问题,但无论如何请听我说完。我在想,如果 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
我知道它与你的主要问题没有直接关系,但它仍然相关,我认为可以很好地利用它。