是什么特别地使 Node.js 比 Apache 更具可伸缩性?

老实说,我还没有完全理解它——我甚至知道 Node.js 是如何工作的,作为一个使用事件模型的单线程。我只是不明白这怎么会比 Apache 好,如果它是单线程的,它怎么会水平扩展。

38890 次浏览

这取决于你如何使用它。Js 默认是单线程的,但是使用(相对而言)新的集群模块可以横向扩展多个线程。

此外,您的数据库需求还将决定节点的伸缩效率。例如,由于 MongoDB 和 node.js 都是事件驱动的,因此在 node.js 中使用 MySQL 不会获得与使用 MongoDB 一样多的好处。

以下连结提供很多不同设定的系统基准: Http://www.techempower.com/benchmarks/

Js 的排名不是最高的,但与其他使用 nginx 的设置相比(表上没有 apache,但足够接近) ,它表现得相当不错。

不过,这也很大程度上取决于您的需求。我相信,如果你只是为静态网站服务,建议你坚持使用更传统的堆栈。然而,人们已经用 node.js 为其他需求做了一些了不起的事情: http://blog.caustik.com/2012/08/19/node-js-w1m-concurrent-connections/(c10k?哈!)

编辑: 值得一提的是,您实际上并没有用 node.js“替换”Apache。您将替换 apache 和 php (在一个典型的灯堆栈中)。

我发现 Tomislav Capan 的这篇博文很好地解释了这一点:
我为什么要使用 Node.js

我对 Node 0.10和 Apache 的要点的解释是:

好的部分

  • Js 可以避免为每个请求旋转线程 ,或者不需要像 Apache 那样处理请求到一组线程的池。因此,它处理请求的开销较少,并且擅长快速响应。
  • Js 可以将请求 的执行委托给一个单独的组件,并关注新的请求,直到委托的组件带着处理过的结果返回。这是异步代码,由事件模型实现。Apache 在池中以串行方式执行请求,当其中一个模块只是在等待任务完成时,不能重用线程。然后,Apache 将对请求进行排队,直到池中的一个线程再次可用。
  • Js 使用 JavaScript ,因此在传递和操作从诸如 MongoDB 之类的外部 web API 源检索到的 JSON 方面非常快,从而减少了每个请求所需的时间。Apache 模块,比如 PHP,可能需要更多的时间,因为它们不能有效地解析和操作 JSON,因为它们需要 调度来处理数据。

坏的部分

注意: 下面列出的大多数不好的部分将会在即将到来的0.12版本中得到改进,这是需要注意的。

  • Js 不擅长处理计算密集型任务 ,因为无论何时它执行长时间运行的任务,它都会将所有其他传入请求排队,这是由于它的单个线程。Apache 通常会有更多的线程可用,而且操作系统会在这些线程之间巧妙而公平地调度 CPU 时间,仍然允许处理新的线程,尽管有点慢。除非 Apache 中的所有可用线程都在处理请求,否则 Apache 也会开始对请求进行排队。
  • Js 不能完全利用多核 CPU ,除非您创建一个 Node.js 集群或者旋转子进程。具有讽刺意味的是,如果执行后两种操作,可能会增加更多的编配开销,这与 Apache 的问题相同。从逻辑上讲,您还可以启动更多的 Node.js 进程,但这不是由 Node.js 管理的。您必须测试您的代码,看看哪些更好; 1)从 Node.js 内部使用集群和子进程进行多线程处理,或者2)使用多个 Node.js 进程。

缓解措施

所有的服务器平台都有一个上限,Node.js 和 Apache 都会在某个时候达到这个上限。

  • 当您有繁重的计算任务时,Node.js 将以最快的速度到达它。
  • 当您向 Apache 抛出大量需要长串行执行的小请求时,Apache 将以最快的速度到达它。

可以做三件事来扩展 Node.js 的吞吐量

  1. 通过设置 集群、使用 子进程或使用诸如 Phusion 乘客之类的多进程协调器,利用多核 CPU
  2. 设置与消息队列 连接的辅助角色。这将是针对计算密集型长时间运行请求的最有效的解决方案; 将它们卸载到工人农场。这将把您的服务器分成两部分: 1)面向公众的接受用户请求的文员服务器,以及2)处理长时间运行任务的私人工作者服务器。两者都与消息队列连接。办事员服务器将消息(传入的长时间运行的请求)添加到队列中。辅助角色侦听传入消息,处理这些消息,并可能将结果返回到消息队列中。如果需要请求/响应,那么文书服务器可以异步等待响应消息到达消息队列。消息队列的例子有 RabbitMQZeroMQ
  3. 设置一个负载平衡器并启动更多的服务器。现在您可以有效地使用硬件并委派长时间运行的任务,您可以横向扩展。如果您有一个负载平衡器,您可以添加更多的文书服务器。使用消息队列,您可以添加更多的工作服务器。您甚至可以在云中设置这些,以便根据需要进行扩展。