jau*_*ume 8 cluster-computing worker-thread node.js
我一直在阅读有关 NodeJS 上的多处理以获得最好的理解并尝试使用我的代码在繁重的环境中获得良好的性能。
虽然我了解利用资源处理负载的不同方式的基本目的和概念,但随着我深入研究,一些问题出现了,似乎我无法在文档中找到特定的答案。
单线程中的 NodeJS:
NodeJS 运行一个我们称之为事件循环的单线程,尽管在后台操作系统和 Libuv 正在处理 I/O 异步任务的默认工作池。
尽管工作人员可能使用不同的核心,但我们应该为事件循环使用单个核心。我想它们最终是由操作系统调度程序排序的。
NodeJS 作为多线程:
使用“worker_threads”库时,在同一个单进程中,每个线程运行不同的v8/Libuv实例。因此,它们共享相同的上下文并在具有“消息端口”和 API 其余部分的线程之间进行通信。
每个工作线程运行其事件循环线程。线程应该在 CPU 内核之间明智地平衡,从而提高性能。我想它们最终是由操作系统调度程序排序的。
问题 1:当工作人员使用 I/O 默认工作人员池时,是否以某种方式共享与其他工作人员池相同的线程?或者每个工人都有自己的默认工人池?
多处理中的NodeJS:
使用“集群”库时,我们将工作拆分到不同的进程中。每个进程都设置在不同的核心上以平衡负载......好吧,主事件循环最终设置在不同的核心中,因此它不会与另一个重事件循环共享核心。这样做听起来很聪明。
在这里,我将与一些 IPC 策略进行交流。
问题 2:这个 NodeJS 进程的默认工作池?他们在哪里?在第一种情况下如预期的那样在其余核心之间保持平衡?然后我猜它们可能与集群的其他工作池位于相同的核心上。说我们正在平衡主线程(事件循环)而不是“进程”不是更好吗?
说了这么多,主要问题是:
问题三:clustering好还是worker_threads好?如果两者都在同一代码中使用,那么两个库如何才能获得最佳性能?或者他们只是可以简单地发生冲突?或者最终是控制权的操作系统?
O. *_*nes 10
每个工作线程都有自己的主循环(libuv 等)。当您使用集群时,每个克隆的 nodejs 进程也是如此。
集群是一种通过该服务器的多个副本对传入 nodejs 服务器的请求进行负载平衡的方法。
工作线程是单个 nodejs 进程将长时间运行的函数卸载到单独线程的一种方式,以避免阻塞自己的主循环。
哪个更好?这取决于您要解决的问题。工作线程用于长时间运行的功能。集群通过并行处理请求,使服务器能够处理更多请求。如果需要,您可以同时使用两者:让每个 nodejs 集群进程使用一个工作线程来处理长时间运行的函数。
作为您决策的第一个近似值:仅当您知道自己有长时间运行的函数时才使用工作线程。
节点进程(无论是来自集群还是工作线程)不会绑定到主机上的特定内核(或英特尔处理器线程);主机的操作系统调度根据需要分配内核。将内核分配给可运行进程时,主机操作系统调度程序将上下文切换开销降至最低。如果您有太多活动的 Javascript 实例 ( cluster instances+ worker threads),主机操作系统将根据其调度算法为它们提供时间片。除了避免过多的 Javascript 实例之外,尝试对操作系统调度程序进行二次猜测几乎没有什么意义。
编辑每个具有任何工作线程的 nodejs 实例都使用单个 libuv 线程池。主 nodejs 进程与其所有工作线程共享一个 libuv 线程池。如果您的 nodejs 程序使用许多工作线程,您可能需要也可能不需要将UV_THREADPOOL_SIZE环境变量设置为大于默认值的值4。
Nodejs 的集群功能使用底层操作系统的 fork/exec 方案为每个集群实例创建一个新的操作系统进程。因此,每个集群实例都有自己的 libuv 池。
如果您正在大规模运行东西,比如说有十多台主机运行您的 nodejs 服务器,那么您可以花时间优化 Javascript 实例。
如果您将 nginx 用作反向代理来处理您的 https 工作,请不要忘记它。它也需要一些处理器时间,但它使用细粒度的多线程,因此除非您有巨大的流量,否则您不必担心它。