NodeJS 什么时候使用集群或worker_threads更好?

smdncfj3  于 2023-01-01  发布在  Node.js
关注(0)|答案(1)|浏览(146)

我一直在阅读关于NodeJS上的多处理的文章,以获得最好的理解,并尝试用我的代码在繁重的环境中获得良好的性能。
虽然我理解了利用资源处理负载的不同方法的基本目的和概念,但随着我的深入,一些问题出现了,似乎我在文档中找不到具体的答案。

单个线程中的NodeJS:

NodeJS运行一个我们称为事件循环的线程,尽管在后台操作系统和Libuv正在处理I/O异步任务的默认工作池。
我们被建议使用一个内核的事件循环,尽管工人可能会使用不同的核心。我猜他们是排序在最后的操作系统调度程序。

NodeJS为多线程:

当使用“worker_threads”库时,在同一个进程中,每个线程运行不同的v8/Libuv示例,因此它们共享相同的上下文,并通过“message port”和API的其余部分在线程之间进行通信。
每个工作线程都运行它的事件循环线程。线程应该在CPU内核之间进行明智的平衡,以提高性能。我猜它们最后是由操作系统调度程序排序的。
问题1:当一个worker使用I/O默认worker池时,是否以某种方式共享了与其他worker池相同的线程?或者每个worker都有自己的默认worker池?

多重处理中的NodeJS:

当使用“集群”库时,我们将工作分配给不同的进程。每个进程都设置在不同的内核上以平衡负载......嗯,主事件循环最终设置在不同的内核中,因此它不会与另一个重事件循环共享内核。这样做听起来很聪明。
在这里我会用一些IPC战术来沟通。
问题2:这个NodeJS进程的默认工作者池?它们在哪里?在第一种情况下,它们在其余的内核之间是平衡的?那么我猜它们可能和集群的其他工作者池在同一个内核上。我们应该说是在平衡主线程(事件循环)而不是“进程”,这不是更好吗?
话虽如此,主要问题是:
问题3:使用集群还是使用worker_threads哪个更好?如果在相同的代码中使用这两个库,两个库如何获得最佳性能?或者它们只是发生冲突?或者最终是操作系统获得控制权?

h7appiyu

h7appiyu1#

每个工作线程都有自己的主循环(libuv等),使用集群时每个克隆的Node.js进程也是如此。
集群是一种在Node.js服务器的多个副本上负载平衡对该服务器的传入请求的方法。
辅助线程是单个Node.js进程将长时间运行的功能卸载到单独线程的一种方式,以避免阻塞自己的主循环。

哪个更好?这取决于您要解决的问题。工作线程用于长时间运行的函数。群集通过并行处理请求,使服务器能够处理更多请求。如果需要,您可以同时使用两个线程:让每个Node.js集群进程为长时间运行的函数使用一个工作线程。

作为您决策的第一近似值:只有当你知道你有长时间运行的函数时才使用工作线程。
节点进程(无论来自集群还是工作线程)都不会绑定到主机上的特定内核(或Intel处理器线程);主机的操作系统调度根据需要分配内核。主机操作系统调度程序在将内核分配给可运行进程时最小化上下文切换开销。如果您有太多活动Javascript示例(cluster instances + worker threads),主机操作系统将根据其调度算法为它们提供时间片。除了避免太多Javascript示例外,尝试事后猜测操作系统调度程序几乎没有意义。

编辑每个Node.js示例(包含任何工作线程)都使用一个libuv线程池。主Node.js进程**与其所有工作线程共享一个libuv线程池。**如果Node.js程序使用许多工作线程,则可能需要或不需要将UV_THREADPOOL_SIZE环境变量设置为大于默认4的值。

js的集群功能使用底层操作系统的fork/exec方案为每个集群示例创建一个新的操作系统进程,因此,每个集群示例都有自己的libuv池。
如果您在大规模运行东西,比如说运行Node.js服务器的主机超过10台,那么您可以花时间优化Javascript示例。
如果你用nginx作为反向代理来处理https的工作,不要忘记它,它也需要一些处理器时间,但是它使用细粒度的多线程,所以除非你有巨大的流量,否则你不必担心它。

相关问题