当前位置: 首页 > 面试题库 >

具有多个并发请求的Node.js服务器,它如何工作?

唐钊
2023-03-14
问题内容

我知道node.js是单线程,异步,无阻塞的I / O。我已经读了很多。例如,PHP每个请求使用一个线程,但是节点仅对所有线程使用一个线程。

假设有三个请求a,b,c同时到达node.js服务器。这些请求中的三个需要大型阻止操作,例如,它们都希望读取相同的大文件。

然后,如何将请求排队,将按什么顺序执行阻塞操作,以及按什么顺序分派响应?当然使用多少个线程?

请告诉我三个请求从请求到响应的顺序。


问题答案:

这是您三个请求的一系列事件的描述:

  1. 三个请求被发送到node.js Web服务器。
  2. 无论哪个请求在其他两个请求之前到达,都会触发Web服务器请求处理程序并开始执行。
  3. 其他两个请求进入node.js事件队列,等待轮到他们。从技术上讲,是否将等待请求在传入的TCP级别上排队还是在node.js内部排队(实际上我不知道)取决于node.js实现的内部,但是出于讨论的目的,所有重要的是,传入事件已排队并且在第一个请求停止运行之前不会触发。
  4. 该第一个请求处理程序将一直执行到遇到异步操作(例如读取文件)为止,然后再无其他操作,直到异步操作完成为止。
  5. 此时,异步文件I / O操作将启动,并且原始请求处理程序将返回(此操作已完成)。
  6. 由于第一个请求(正在等待文件I / O)现在已经返回,因此node.js引擎现在可以将下一个事件从事件队列中拉出并启动它。这是到达服务器的第二个请求。它在第一个请求时将经历相同的过程,并将一直运行直到无其他事情为止(并且还在等待文件I / O)。
  7. 当第二个请求返回系统时(因为它正在等待文件I / O),则第三个请求可以开始运行。它将遵循与前两个相同的路径。
  8. 现在,当第三个请求也正在等待I / O并返回系统时,node.js可以自由地将下一个事件从事件队列中拉出。
  9. 此时,所有三个请求处理程序都同时处于“运行中”状态。实际上一次只能运行一次,但是所有一次都可以运行。
  10. 事件队列中的下一个事件可能是某个其他事件或某个其他请求,也可能是前三个文件I / O操作之一的完成。队列中下一个事件将开始执行。假设它是第一个请求的文件I / O操作。此时,它将调用与该第一个请求的文件I / O操作相关联的完成回调,并且该第一个请求开始处理文件I / O结果。然后,此代码将继续运行,直到完成整个请求并返回,或者开始其他异步操作(如更多文件I / O)并返回为止。
  11. 最终,第二个请求的文件I / O将准备就绪,该事件将从事件队列中拉出。
  12. 然后,对第三个请求相同,最终所有三个请求都将完成。

因此,即使实际上实际上只有一个请求同时在执行,多个请求也可以同时处于“处理中”或“运行中”状态。有时这称为协作多任务,而不是通过具有多个本机线程的“抢先式”多任务,系统可以随时在这些线程之间自由切换,给定的Javascript线程运行直到返回系统,然后再返回,只有这样,才能开始运行另一段Javascript。因为一段Javascript可以启动非阻塞异步操作,所以Javascript线程可以在其异步操作仍处于挂起状态时返回到系统(使其他Javascript片段可以运行)。这些操作完成后,

单螺纹

这里的关键点是,给定的Javascript线程将一直运行,直到返回系统为止。如果在执行过程中启动了一些异步操作(例如文件I /
O或网络连接),那么当这些事件结束时,它们会将一个事件放入事件队列中,并且当JS引擎完成运行任何事件之前,它,该事件将得到处理,并将导致调用回调,并且该回调将轮流执行。

与多线程模型相比,这种单线程性质极大地简化了并发的处理方式。在每个请求都启动其自己的线程的完全多线程环境中,所有希望共享的数据,甚至是一个简单的变量,都必须遵守竞争条件,并且必须使用互斥体进行保护,然后任何人才能读取它。

在Javascript中,因为没有多个请求的并发执行,所以对于简单的共享变量访问不需要互斥体。从定义上看,一段Javascript正在读取一个变量,此时没有其他Javascript在运行(单线程)。

Node.js确实使用线程

注意的一种技术区别是,只有Javascript的执行是单线程的。node.js内部构件确实将线程本身用于某些方面。例如,异步文件I /
O实际上使用本机线程。网络I / O实际上并不使用线程(它使用本机事件驱动的网络)。

但是,在node.js内部使用线程不会直接影响Javascript执行。一次仅执行一个Java线程。

比赛条件

启动异步操作时,在修改状态的过程中仍可能存在争用条件,但是这种方法比多线程环境中的方法少见,而且更容易识别和保护这些情况。作为可能存在的竞争条件的示例,我有一个简单的服务器,该服务器使用间隔计时器每10秒从多个温度探测器读取一次读数。它从所有这些温度读数中收集数据,并且每小时将其写出到磁盘。它使用异步I
/ O将数据写入磁盘。但是,由于使用了许多不同的异步文件I / O操作将数据写入磁盘,因此间隔计时器可能会在某些异步文件I /
O操作之间触发,从而导致服务器所在的数据写入磁盘的中间要修改。这很糟糕,可能导致写入不一致的数据。在一个简单的世界中,可以通过在开始将所有数据复制到磁盘之前对其进行复制来避免这种情况,因此,如果在将数据写入磁盘时出现新的温度读数,则该复制将不会受到影响,并且代码仍将一组一致的数据写入磁盘。但是,对于此服务器,数据可能很大,而服务器上的内存却很小(这是Raspberry
Pi服务器),因此在内存中复制所有数据是不切实际的。副本将不受影响,并且代码仍将一致的数据集写入磁盘。但是,对于此服务器,数据可能很大,而服务器上的内存却很小(这是Raspberry
Pi服务器),因此在内存中复制所有数据是不切实际的。副本将不受影响,并且代码仍将一致的数据集写入磁盘。但是,对于此服务器,数据可能很大,而服务器上的内存却很小(这是Raspberry
Pi服务器),因此在内存中复制所有数据是不切实际的。

因此,可以通过在将数据写入磁盘的过程中设置一个标志,然后在将数据写入磁盘后清除该标志来解决该问题。如果在设置此标志的同时触发间隔计时器,则会将新数据放入单独的队列中,并且不会修改正在写入磁盘的核心数据。将数据写入磁盘后,它将检查队列并将发现的所有温度数据添加到内存中的温度数据中。将保留正在写入磁盘的过程的完整性。每当此“竞赛条件”被击中并且由于该原因数据进入队列时,我的服务器都会记录一个事件。而且,瞧,它确实每隔一段时间就会发生一次,并且保存数据完整性的代码也起作用了。



 类似资料:
  • 问题内容: 关于此问题: 将cookie从一个请求传输/传递到nodejs /protractor中的另一个请求 我又拿了一个 我如何查看通过nodejs执行的完整请求(标头+正文)? 问题答案: 是的,您可以…您可以从完整的响应正文访问完整的请求- 我有一个如下所示的通用完整响应结构 您可以通过如下代码访问

  • 我是套接字编程新手,我在理解serversocket方面有问题。假设我们创建一个这样的serversocket: 然后在一些东西之后,在缓冲区中写一些东西: 我的问题是:连接如何理解哪个客户端应该得到服务器的响应?我们的积压工作是20个,20个客户端可以同时连接到服务器套接字(据我所知)。

  • 问题内容: 我正在尝试允许javascript与Node.js服务器通信。 POST请求(Web浏览器) 现在,Node.js服务器代码如下所示。在用于GET请求之前。我不确定如何使其与POST请求一起使用。 服务器(Node.js) 在此先感谢您的帮助。 问题答案: 以下代码显示了如何从HTML表单读取值。正如@pimvdb所说,您需要使用request.on(’data’…)来捕获正文的内容。

  • 问题内容: 我正在尝试通过一个请求将数据从一个node.js服务器发送到另一个node.js服务器。我在“客户端” node.js中执行的操作如下: 该块或多或少是从node.js网站获取的,因此应该正确。我唯一看不到的是如何在变量中包括用户名和密码以进行实际登录。这是我处理服务器node.js中的数据的方式(我使用express): 如何将这些和字段添加到变量中以使其登录? 谢谢 问题答案: 发

  • 问题内容: 我知道Node.js使用单线程和事件循环来处理仅一次处理一个请求的请求(这是非阻塞的)。但是,这是如何工作的,可以说有10,000个并发请求。事件循环会处理所有请求吗?那会不会花费太长时间? 我还不了解(至今)如何比多线程Web服务器更快。我知道多线程Web服务器的资源(内存,CPU)会更昂贵,但是会不会更快?我可能是错的。请说明该单线程在许多请求中的运行速度如何,以及在处理诸如10,

  • 问题内容: 我想做的事情: 使用jquery ajax请求将一些数据(例如json)简单地发送到node.js http服务器。 由于某种原因,我无法在服务器上获取数据,因为它从不触发请求的“数据”事件。 客户代码: 服务器代码: 如我所说,它永远不会进入请求的“数据”事件。 注释: 1.记录“收到请求”消息; 2.响应很好,无法使用数据将其返回给客户端。 有什么帮助吗?我想念什么吗? 谢谢大家。