何时更好地使用聚类或工作线程?

26

我一直在学习NodeJS上的多线程处理,以便更好地理解和提高代码在高负载环境下的性能。

虽然我理解如何利用资源来处理负载所需的基本目的和概念,但当我进一步深入时,会有一些问题,而且似乎在文档中找不到具体的答案。

NodeJS单线程:

NodeJS运行一个单线程,我们称之为事件循环,尽管在后台操作系统和Libuv正在处理I/O异步任务的默认工作池。

我们应该使用单个核心来处理事件循环,尽管工人可能使用不同的核心。我猜他们最终会被操作系统调度器排序。

NodeJS多线程:

使用“worker_threads”库时,在同一单个进程中,每个线程都运行不同的v8 / Libuv实例。因此,它们共享相同的上下文,并使用“消息端口”和其他API在线程之间进行通信。

每个工作线程都运行其自己的事件循环线程。线程应该明智地平衡在CPU核心之间,从而提高性能。我猜他们最终会被操作系统调度器排序。

问题1:当工作线程使用I/O默认工作池时,它们会与其他工作池共享相同的线程吗?还是每个工作者都有自己的默认工作者池?

NodeJS中的多进程:

当使用"cluster"库时,我们将工作分配给不同的进程。每个进程都设置在不同的核心上以平衡负载...好吧,最终设置在不同核心上的是主事件循环,因此它不与其他繁重的事件循环共享核心。听起来这么做很聪明。

在这里我将使用一些IPC策略进行通信。

问题2:这个NodeJS进程的默认工作池在哪里?像第一个情况中期望的那样在其他核心之间平衡吗?那么他们可能与集群的其他工作池在同一个核心上。我们是否应该说我们正在平衡主线程(事件循环)而不是"进程"呢?

所有这些都说了,主要问题是:

问题3:使用集群还是worker_threads更好?如果两者都在同一代码中使用,如何让这两个库达到最佳性能?它们会冲突吗?还是最终权限属于操作系统?

1个回答

38
每个工作线程都有自己的主循环(libuv等)。当您使用集群时,每个克隆的Node.js进程也是如此。
集群是一种将传入请求平衡到多个服务器副本上的方法。
工作线程是单个Node.js进程将长时间运行的函数卸载到单独的线程中,以避免阻塞其自身的主循环。
哪个更好?这取决于您要解决的问题。工作线程适用于长时间运行的功能。通过并行处理请求,集群使服务器能够处理更多请求。如果需要,请为每个Node.js集群进程使用工作线程来处理长时间运行的函数。
作为决策的第一近似:仅在知道具有长时间运行的函数时才使用工作线程。
节点进程(无论是来自集群还是工作线程)不会绑定到主机机器上的特定核心(或英特尔处理器线程);主机的OS调度根据需要分配核心。主机OS调度程序在分配可运行进程的核心时最小化上下文切换开销。如果有过多的活动JavaScript实例(cluster instances + worker threads),主机OS将根据其调度算法为它们分配时间片。除了避免过多的JavaScript实例外,试图猜测OS调度程序几乎没有任何意义。
每个Node.js实例,无论有多少个工作线程,都使用单个libuv线程池。主Node.js进程与其所有工作线程共享单个libuv线程池。如果您的Node.js程序使用许多工作线程,则可能需要将UV_THREADPOOL_SIZE环境变量设置为大于默认值4的值。
Node.js的集群功能使用底层OS的fork / exec方案为每个集群实例创建一个新的OS进程。因此,每个集群实例都有自己的libuv池。
如果您在规模上运行东西,比如有超过十台主机运行您的Node.js服务器,则可以花时间优化JavaScript实例。
如果您将其用作反向代理以处理https工作,请不要忘记nginx。它也需要一些处理器时间,但它使用细粒度多线程,因此除非您有大量流量,否则不必担心它。

谢谢,@O. Jones。我仍然想知道默认的工作池是如何分配的,例如每个主线程是否都有自己的池或者它是以某种方式共享的。 - jaume
所以,请告诉我,如果我正确理解了您的编辑:用户创建的工作线程有自己的池。而且集群中新进程中的主线程也有自己的池。因此,我们可以说任何来自任何来源的主线程(事件循环)都有自己的后台线程池,由其自己的libuv实例处理。我是对的吗? - jaume
2
在工作线程上,它们与创建它们的主线程共享一个池。 - O. Jones
我不明白。在工作线程中,每个线程都有自己的V8和Libuv实例。Libuv是处理工作池的组件。这个池如何在不同的Libuv实例之间共享?或者我哪里错了? - jaume
1
“一个主要的Node.js进程与所有工作线程共享单个libuv线程池”这句话是不正确的。它也与您之前所说的相矛盾,即“每个工作线程都有自己的主循环(libuv等)。” - Muhammad Muzammil
阅读您的回答让我感到困惑。一开始您说工作线程有自己的线程池,而最后又说它们共享一个单一的线程池。 - tnvr_98

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接