是啥让 Node.js 比 Apache 更具可扩展性?

Posted

技术标签:

【中文标题】是啥让 Node.js 比 Apache 更具可扩展性?【英文标题】:What specifically makes Node.js more scalable than Apache?是什么让 Node.js 比 Apache 更具可扩展性? 【发布时间】:2013-05-10 20:11:05 【问题描述】:

说实话,我还没有完全理解它——我什至理解 Node.js 是如何工作的,作为使用事件模型的单线程。我只是不明白这比 Apache 好,以及如果它是单线程的,它是如何水平扩展的。

【问题讨论】:

【参考方案1】:

我发现 Tomislav Capan 的这篇博文解释得很好:Why The Hell Would I Use Node.js? A Case-by-Case Introduction

与 Apache 相比,我对 Node 0.10 要点的解释:

好的部分

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

坏处

注意:下面列出的大部分不好的部分将在即将发布的 0.12 版本中得到改进,请注意。

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

缓解措施

所有服务器平台都有上限。 Node.js 和 Apache 都将在某个时候达到它。

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

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

    利用多核 CPU,通过设置 cluster、使用 child processes 或使用像 Phusion Passenger 这样的多进程编排器。 设置与消息队列相关的辅助角色。这将是针对计算密集型长时间运行请求的最有效解决方案;将它们卸载到工人农场。这会将您的服务器分成两部分; 1) 接受用户请求的面向公众的文书服务器,以及 2) 处理长时间运行任务的私有工作服务器。两者都与消息队列相连。文书服​​务器将消息(传入的长时间运行的请求)添加到队列中。工作角色侦听传入的消息,处理这些消息,并可能将结果返回到消息队列中。如果需要请求/响应,那么文书服务器可以异步等待响应消息到达消息队列。消息队列的示例是 RabbitMQ 和 ZeroMQ。 设置负载平衡器并启动更多服务器。现在您可以高效地使用硬件并委派长时间运行的任务,您可以水平扩展。如果您有负载平衡器,则可以添加更多文书服务器。使用消息队列,您可以添加更多工作服务器。您甚至可以在云端进行设置,以便按需扩展。

【讨论】:

这是一个很好的答案。特别是关于 MQ 的提示。想知道它们有什么用。谢谢! 任何计算密集型任务都应该异步完成。如果不严重依赖长时间运行的任务的异步执行,Node 实际上将无法使用。这是节点可扩展性的主要特征(就单个实例而言),并且在此要牢记在心。 好点@AdamTolley。在此基础上,我所说的计算密集型任务是指不能轻易分解为多个异步部分的任务。只需在 CPU 上同步完成的事情。例如,渲染图像。如果您无法将异步代码委派或卸载到另一个 CPU 或进程,那么异步代码将无济于事。但是,如果您可以分解一项任务,那么其他异步任务可以像操作系统一样按时间分片。 纯 TCP 协议胜过一切,但不适用于公共站点主机。一些商人每月支付 3,000 美元购买云服务器,而不是使用可以满足的普通主机。【参考方案2】:

这取决于你如何使用它。 Node.js 默认是单线程的,但是使用(相对)新的集群模块,您可以跨多个线程水平扩展。

此外,您的数据库需求还将决定节点扩展的有效性。例如,将 mysql 与 node.js 一起使用不会像使用 MongoDB 那样为您带来几乎一样的好处,因为 MongoDB 和 node.js 都是事件驱动的性质。

以下链接提供了许多不同设置的系统基准测试: http://www.techempower.com/benchmarks/

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

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

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

【讨论】:

很棒的答案,这实际上增加了我的问题。首先,我不太明白那家伙做了什么特别的事——他为每个可用的核心生成了 1 个工人,是吗?他在那里做的那个网格巫术是什么?如果他所做的只是服务于一个 Hello 世界,为什么他需要通过节点进行消息传递!?另外,我几乎不知道那里的任何框架。例如,Go,我认为它只是一种编程语言。有什么地方可以让我大致了解正在发生的事情,那些实际上是什么以及做什么?那真是太好了。谢谢! 他实际上只为他的服务器使用了 1 个工作进程。他正在做的是使用 Amazon EC2 动态生成 500 个客户端实例来创建连接(每个 2000 个,总共 100 万个),并在所有这些客户端之间来回发送消息时保持与单进程 Web 服务器的连接。我应该从他的第一篇文章开始链接,他从 10 万个连接开始,然后一路向上 (blog.caustik.com/2012/04/08/…)。就 Go 等而言,我建议只用谷歌搜索它们。 Apache太好了,支持国际HTTP轮询,哈哈

以上是关于是啥让 Node.js 比 Apache 更具可扩展性?的主要内容,如果未能解决你的问题,请参考以下文章

是啥让 nimble 比 shiro 更好?

是啥让 nativescript 比 ionic 更好

是啥让移动对象比复制更快?

是啥让 PostgreSQL 比 MySQL 更先进? [关闭]

是啥让 SPI 比 I2C 协议更快 [关闭]

除了多路复用和服务器推送之外,是啥让 http/2 比 http/1 更快?