多核机器上的Node.js

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

那么如何扩展多核CPU和多CPU服务器呢? 毕竟,尽可能快的单线程服务器是非常好的,但是对于高负载,我想要使用多个CPU。 同样的,使应用程序更快 – 看来今天的方式是使用多个CPU并行任务。

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

[ 这篇文章是最新的2012-09-02(比以上更新)。 ]

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

是的,Node.js是一个单线程的进程。 这是一个非常慎重的devise决定,并且不需要处理locking语义。 如果你不同意这一点,你可能还没有意识到debuggingmultithreading代码是多么的艰巨。 有关Node.js过程模型的更深入的解释,以及为什么它以这种方式工作(以及为什么它不会支持多个线程),请阅读我的其他post 。

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

两种方式:

  • 对于图像编码等繁重的计算任务,Node.js可以启动subprocess或将消息发送到其他工作进程。 在这个devise中,你将有一个线程来pipe理事件stream和N个进程,执行繁重的计算任务,并咀嚼其他15个CPU。
  • 为了在web服务上扩展吞吐量,您应该在一个框上运行多个Node.js服务器,每个核心运行一个,并在它们之间拆分请求stream量。 这提供了极好的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); } 

工人们将竞争接受新的关系,而最less的过程最有可能获胜。 它工作得很好,可以在多核心盒上很好地扩大吞吐量。

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

  1. 在像Nginx或Apache这样的networking代理后面运行Node.js服务 – 可以进行连接控制(除非你想让重载条件完全closures),重写URL,提供静态内容和代理其他子服务。

  2. 定期回收您的工作stream程。 对于一个长期运行的过程,即使是一个小的内存泄漏最终会加起来。

  3. 安装日志收集/监视


PS:亚伦和克里斯托弗之间在另一篇文章的评论之间进行了讨论(截至撰写本文,其最高职位)。 有几点意见:

  • 共享套接字模型非常方便,允许多个进程在单个端口上侦听并竞争接受新的连接。 从概念上讲,你可以想到Apache预先执行这个操作,但有一个重要的警告,即每个进程只能接受一个连接,然后死掉。 Apache的效率损失是在分配新进程的开销中,并且与套接字操作无关。
  • 对于Node.js,让N个工作者在一个套接字上竞争是非常合理的解决scheme。 另一种方法是设置一个像Nginx一样的在线前端,并将这个代理stream量分配给各个工作人员,在工作人员之间交替分配新的连接。 这两种解决scheme具有非常相似的性能特征 而且,正如我上面提到的,无论如何,你可能希望有Nginx(或者另一种)面向你的节点服务,这里的select真的在两者之间:

共享端口: 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) ...}

对于单独的端口设置有一些好处(可能会减less进程之间的耦合,具有更复杂的负载平衡决策等),但是build立起来的确是更多的工作,并且内置的集群模块是低的复杂的select,适用于大多数人。

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

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

如果你想立即弄脏手,请检查spark2 Forever模块。 它使产卵多节点进程非常简单。 它处理设置端口共享,所以它们都可以接受到同一个端口的连接,并且如果你想确保一个进程在/当它死亡的时候重新启动,它也会自动重新生成。

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

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

为了更简单的需要,您可以在不同端口号上启动多个节点副本,并将负载平衡器放在它们的前面。

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

join类似的东西

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

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

现在,很多人也更喜欢PM2 ,它为您处理群集,并提供一些很酷的监控function 。

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

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

 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); } 

未来版本的节点将允许你分叉一个进程并将消息传递给它,Ryan已经声明他想find某种方式来共享文件处理程序,所以它不会是一个简单的Web Worker实现。

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

Spark2基于Spark,现在不再维护了。 Cluster是它的后继者,它有一些很酷的function,比如每个CPU核心产生一个工作进程,并重新启动死亡的工作人员。

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

这里的新的孩子是LearnBoost的“Up” 。

它提供了“零停机重新加载”,并创build了多个工作人员(默认情况下是CPU的数量,但是它是可configuration的),以提供最好的世界。

这是新的,但似乎是相当稳定的,我在目前的一个项目中愉快地使用它。

节点Js支持集群来充分利用你的CPU。 如果你不是在集群上运行它,那么你可能正在浪费你的硬件function。

Node.js中的群集允许您创build可以共享相同服务器端口的单独进程。 例如,如果我们在端口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. } 

检查这篇文章的完整教程

也可以将Web服务devise为多个独立的侦听unix套接字的服务器,以便将数据处理等function推送到独立的进程中。

这与大多数scrpting / database web服务器体系结构类似,cgi进程处理业务逻辑,然后通过unix套接字将数据推送到数据库。

不同之处在于数据处理是作为监听端口的节点networking服务器来编写的。

这是更复杂的,但最终是多核心发展的地方。 为每个Web请求使用多个组件的多进程体系结构。

可以通过在运行一个NodeJS进程的多个盒子前面使用纯TCP负载平衡器(HAProxy)来将NodeJS扩展到多个盒子。

如果你有共同的知识分享所有的实例,你可以使用一个中央Redis商店或类似的,然后可以从所有stream程实例(例如从所有框)访问,

Interesting Posts