非阻塞Web服务器如何工作?

时间:2015-08-10 04:27:45

标签: node.js nonblocking

例如,传统的一个:

var dt;
dt = 
$('#datetimepicker3').datetimepicker({
    inline:true,
    minDate: 0,
    format:'m/d/Y H:i',
    formatDate:'d/m/Y'
});

非阻止Web服务器如何工作?例如,节点?

[client] 0s GET /test  
[server] 1s got request
[server] 2s query db
[server] 3s db return 
[server] 4s return response
[client] 5s get response

所以传统的一个将花费5s而非阻塞一个只需3s或4s ??

1 个答案:

答案 0 :(得分:2)

具有使用非阻塞I / O的请求处理程序的非阻塞Web服务器可以在任何给定请求等待来自非阻塞I / O请求的结果时交错处理其他请求,并且它可以执行所有这些操作只有一个帖子。

所以,如果第一个请求有这个事件序列:

5ms [r1 - sync: receive incoming request, send read request to database]
100ms [r1 - async: read request from database returns data]
5ms [r1 - sync: convert data to proper form for the response]
5ms [r1 - async: send response back to client]

以上操作标记为" sync:"是非阻塞服务器的主线程忙于工作的操作。如果此非阻塞服务器是单线程的,则此时不会提供其他任何操作。如果在此期间有其他请求进入,那么它将排队 - 等待主线程不忙的点。

上述序列中排队等待处理的新请求的第一个机会是在100ms异步数据库读取操作中。

所以,让我们假设在上述请求之后的1ms内发出了另一个请求,这次它是一个具有正常进展的写请求:

5ms [r2 - sync: receive incoming request, send write request to database]
500ms [r2 - async: write request returns result]
5ms [r2 - async: send response back to client]

然后,这两个请求将交织在一起:

将收到

r1,初始处理将在其上完成,然后它将把它的读取请求发送到数据库。此时,r1完成,直到读取请求从数据库返回,因此主服务器线程现在可用于提供其他请求。

如果r2在队列中等待,则启动r2请求。初始处理在其上完成,并将其写入请求发送到数据库。

此时,有两个数据库操作并行运行,一个从r1读取,另一个从r2写入,都来自一个服务器线程。

现在,由于这两个请求都在进行中,服务器线程暂时无关(如果有的话,它可以记录其他传入请求)。

然后,在r1请求发送其读取请求后100ms,数据库将触发其回调以指示数据可用。因此,该回调开始运行,然后执行r1请求的最后两个步骤,并将响应发送回其客户端。

然后,在r2请求发送其写请求500ms后,数据库将触发其回调以指示写操作已完成。这样回调就开始运行,然后执行r2请求的最后两步,并将响应发送回客户端。

这里的操作点是没有任何先发制人。给定请求同步运行,直到它触发异步操作。此时,它完成了当时可以处理的任何事情,然后服务器线程可以自由地为其队列中等待的其他事件提供服务(其他新请求进入或其他等待运行的请求的异步回调) 。从队列中拉出下一个项目,它将一直运行直到完成。下一个项目从队列中拉出并运行直到完成,等等......

非阻塞单线程服务器有一些优点,例如node.js。

  1. 在执行I / O的同时,它们可以非常有效地处理飞行中的一堆请求。这是因为他们可以使用一个线程处理所有主要处理,即使同时有一堆请求全部在飞行中。非阻塞服务器必须同时为飞行中的每个请求创建系统线程,这在服务器端的资源密集程度更高,多线程多任务的额外开销也导致整体效率降低操作,如果你只看一下服务器可以处理的请求/秒的数量,因为一些服务器CPU用于在线程之间进行任务切换。

  2. 使用单线程node.js设计,线程之间的同步问题更少,因为代码都是非抢占式的。请求从一个请求处理切换到某个其他请求仅发生在请求发出非阻塞I / O请求的位置。这可以极大地简化大量编程,例如访问共享资源,因为在node.js模型中,您不必使用互斥锁来保护共享数据。这不仅可以显着减少编写代码的复杂性,而且还可以减少令人讨厌的并发错误的机会。 node.js程序中仍然存在一些并发问题,但它们的数量要少得多,而且编码通常也更简单。

  3. 非阻塞单线程样式的缺点有时必须编码:

    1. 长时间运行的同步计算将" hog"主线程和其他请求在此期间不会获得任何周期。虽然有一个长期运行的计算不能进行I / O的半罕见,但它可能会发生。一个常见的解决方法是将这些长时间运行的计算移到另一个进程中,由OS进行时间分割,以便主线程可以执行其他操作。

    2. 非阻塞I / O代码需要一些习惯来学习如何编写,并且写入比阻塞I / O代码更复杂。 Prom通常是使这段代码健壮,易读和易于编写(特别是处理错误时)的一大帮助。

    3. 如果您的服务器有多个CPU,则单个node.js线程不会利用它们,因为它主要只使用一个CPU。这通常通过使用群集来解决,群集将为每个CPU运行单独的node.js进程,并将传入的请求传递给任何可用的群集服务器。