Nodejs-线程池大小为四时,可以同时运行的最大线程数是多少?

时间:2020-08-12 04:41:37

标签: node.js multithreading threadpool event-loop

要求是每秒1000个并发请求和IO操作,例如对每个请求的数据库查询。由于nodejs在事件循环上工作,它将IO操作分配给线程池,但是线程池的默认大小为4,因此同时最多可以有4个线程(IO操作)工作,其余线程必须在队列中等待。一旦任何线程完成执行,便可以处理。

查询1-我们可以根据需要将线程池大小增加到N个吗,它会提高性能还是会降低性能?

查询2-如何在nodejs中实现以上要求?

查询3-Nodejs是此要求或其他建议(例如golang)的空闲选择

3 个答案:

答案 0 :(得分:2)

node.js上的网络I / O操作在主线程上运行。

是的,node.js除了主线程外还产生了四个线程,但是它们都不用于网络I / O(例如数据库操作)。线程是:

  1. DNS解析器(因为大多数操作系统为此仅提供同步API)

  2. 文件系统API(因为这样做很麻烦,无法跨平台进行异步操作)

  3. 加密(因为这使用CPU)

  4. Zlib(zip压缩)

除非您自己生成worker_threads,否则其他所有内容都不会使用线程。有关更多信息,请参见节点自己的文档:https://nodejs.org/en/docs/guides/dont-block-the-event-loop/。不要依赖不是来自node.js项目本身的信息,例如youtube或中级文章,这些文章说节点I / O使用线程池-他们不知道自己在说什么。

增加线程池大小不会对网络I / O产生任何影响,因为node.js根本没有任何代码可以使网络I / O利用额外的线程。如果要将负载分散到多个处理器中,可以使用群集。您可以编写自己的集群代码,也可以使用诸如pm2之类的进程管理器的集群模式将连接传递给您的进程。

如果节点仅使用一个线程,怎么能声称自己具有高性能!

大多数非系统程序员不会意识到的是,等待I / O占用的CPU时间恰好为零。通过生成线程来执行此操作意味着您正在分配大量的RAM,并且所有这些线程通常都使用 zero CPU时间(设想生成1024个线程,每个线程根本不使用CPU)。当这些线程(或在主线程为node.js的情况下)正在等待来自数据库的1000条回复时,操作系统会将这些请求排队放入一系列数据包中,然后将其发送到您的网卡中,然后由网卡将其发送到数据库中一次一点点-是的,它的核心I / O不是并行的(除非您在多个网卡上使用中继)。因此,大多数繁重的工作都是通过以太网完成的,而操作系统会暂停您的进程(等待)。

node.js的作用是在请求等待时发出另一个请求。这就是非阻塞的意思。节点在处理所有其他请求之前不会等待请求完成。这意味着默认情况下,您在node.js中发出的所有请求都是并发的-它们不等待其他请求完成。

在请求完成侧,从服务器收到的任何响应都会触发节点搜索事件队列(由于此时队列中的任何项目都可以随时完成,因此这实际上只是一个设置),并找到相应的回调进行调用。执行回调要做会占用CPU时间,但不等待网络请求。

这就是为什么像node.js这样的系统可以与多线程系统竞争的原因。实际上,在某些情况下,它的性能可能会优于多线程系统,因为在同一线程上执行此操作意味着您不需要锁(互斥或信号量),并且避免了上下文切换的开销(当操作系统将一个线程置于睡眠状态时,将所有副本将值保存到RAM中,然后唤醒另一个线程,将另一个寄存器的值复制回RAM中以用于新进程。

答案 1 :(得分:1)

libuv中的网络套接字是无阻塞的(即不在该线程池上)。首先建立测试工具。使用默认值可能会更好。

要增加线程池的大小,请将环境变量UV_THREADPOOL_SIZE=N设置为1024。

$ node --help
...
Environment variables:
...
UV_THREADPOOL_SIZE            sets the number of threads used in libuv's threadpool

答案 2 :(得分:1)

nodejs中的网络不使用线程池,因此切换不会影响您的网络I / O吞吐量。联网使用的OS API已经是异步且无阻塞的。

在处理传入请求时运行的Javascript也不使用线程池。

磁盘I / O确实使用了线程池,但是如果您仅访问一个物理磁盘驱动器,那么扩大线程池可能不会给您带来很多好处,因为只有一个物理磁盘伺服器只能放在一个位置无论如何,如果并行运行20个磁盘请求,如果它们都在争夺相同的磁盘头位置,则不一定对您有帮助。实际上,当操作系统尝试在所有不同线程之间进行时间片划分时,甚至可能使情况变得更糟,从而导致磁盘头的移动超出了为每个线程服务的最佳范围。

要每秒处理1000个请求,您将必须进行基准测试并测试瓶颈所在。如果我猜想我敢打赌,瓶颈将是您的数据库,在这种情况下,重新配置nodejs设置并不是您需要集中精力的地方。但是,无论如何,只有在确定了特定应用程序中的瓶颈所在后,您才能正确地找出哪些选项可以帮助您解决该瓶颈。另外,请记住,每秒处理1000个请求意味着您不能为每个请求运行Java脚本,而每个请求花费的时间超过1毫秒。因此,您可能也必须对服务器进行群集(通常,服务器硬件中每个物理CPU内核一个群集)。因此,如果您有8核服务器,则可以设置8节点集群。

例如,如果您的Nodejs进程中的CPU受限于您的自己的Javascript的运行,那么也许您想实现nodejs集群以使多个CPU都运行不同的请求。但是,如果真正的瓶颈在您的数据库中,则对您的nodejs请求处理程序进行群集将无法解决数据库的瓶颈。

进行基准测试,测量,基于更改的数据得出理论,设计特定的测试以进行测量,然后实施其中一种理论并进行测量。根据您的测量进行调整。您只有通过先测量,进行适当的调整然后测量进度,才能真正正确地做到这一点(而不会浪费大量时间浪费在无效的方向上)。