Node JS 架构 – 单线程事件循环

今天我们将深入研究Node JS的架构和单线程事件循环模型。在我们之前的文章中,我们已经讨论了Node JS的基础知识、组件和安装。

Node JS 架构

在开始一些Node JS编程示例之前,了解Node JS的架构是很重要的。我们将在本文中讨论“Node JS是如何在底层工作的,它遵循什么类型的处理模型,如何通过单线程模型处理并发请求”等问题。

Node.js 单线程事件循环模型

正如我们已经讨论过的那样,Node JS应用程序使用“单线程事件循环模型”架构来处理多个并发客户端。有许多Web应用程序技术,如JSP、Spring MVC、ASP.NET、HTML、Ajax、jQuery等。但是所有这些技术都遵循“多线程请求-响应”架构来处理多个并发客户端。我们已经很熟悉“多线程请求-响应”架构,因为大多数Web应用程序框架都使用它。但是为什么Node JS平台选择了不同的架构来开发Web应用程序?多线程和单线程事件循环架构之间的主要区别是什么?任何Web开发人员都可以轻松学习Node JS并开发应用程序。但是如果不了解Node JS内部机制,就不能很好地设计和开发Node JS应用程序。因此,在开始开发Node JS应用程序之前,我们首先将学习Node JS平台的内部机制。

Node JS 平台

Node.js 平台采用 “单线程事件循环” 架构来处理多个并发客户端。那么它是如何处理并发客户端请求而不使用多个线程的呢?什么是事件循环模型?我们将一一讨论这些概念。在讨论 “单线程事件循环” 架构之前,我们先来了解一下著名的 “多线程请求-响应” 架构。

传统网络应用处理模式

没有使用Node JS开发的任何Web应用程序通常遵循“多线程请求-响应”模型。简单来说,我们可以将这个模型称为请求/响应模型。客户端向服务器发送请求,然后服务器根据客户端的请求进行一些处理,准备响应并将其发送回客户端。该模型使用HTTP协议。由于HTTP是一种无状态协议,所以这个请求/响应模型也是无状态模型。因此,我们可以将其称为请求/响应无状态模型。然而,这个模型使用多线程来处理并发的客户端请求。在讨论这个模型的内部机制之前,请先看一下下面的图表。请求/响应模型处理步骤:

  • Clients Send request to Web Server.
  • Web Server internally maintains a Limited Thread pool to provide services to the Client Requests.
  • Web Server is in infinite Loop and waiting for Client Incoming Requests
  • Web Server receives those requests.Web Server pickup one Client Request
    Pickup one Thread from Thread pool
    Assign this Thread to Client Request
    This Thread will take care of reading Client request, processing Client request, performing any Blocking IO Operations (if required) and preparing Response
    This Thread sends prepared response back to the Web Server
    Web Server in-turn sends this response to the respective Client.

服务器在无限循环中等待并执行上述所有步骤,适用于n个客户端。这意味着该模型为每个客户端请求创建一个线程。如果更多客户端请求需要阻塞的IO操作,那么几乎所有的线程都会忙于准备他们的响应。然后剩下的客户端请求将需要等待更长的时间。图表描述:

  • Here “n” number of Clients Send request to Web Server. Let us assume they are accessing our Web Application concurrently.
  • Let us assume, our Clients are Client-1, Client-2… and Client-n.
  • Web Server internally maintains a Limited Thread pool. Let us assume “m” number of Threads in Thread pool.
  • Web Server receives those requests one by one.Web Server pickup Client-1 Request-1, Pickup one Thread T-1 from Thread pool and assign this request to Thread T-1

    Thread T-1 reads Client-1 Request-1 and process it
    Client-1 Request-1 does not require any Blocking IO Operations
    Thread T-1 does necessary steps and prepares Response-1 and send it back to the Server
    Web Server in-turn send this Response-1 to the Client-1

    Web Server pickup another Client-2 Request-2, Pickup one Thread T-2 from Thread pool and assign this request to Thread T-2

    Thread T-2 reads Client-1 Request-2 and process it
    Client-1 Request-2 does not require any Blocking IO Operations
    Thread T-2 does necessary steps and prepares Response-2 and send it back to the Server
    Web Server in-turn send this Response-2 to the Client-2

    Web Server pickup another Client-n Request-n, Pickup one Thread T-n from Thread pool and assign this request to Thread T-n

    Thread T-n reads Client-n Request-n and process it
    Client-n Request-n require heavy Blocking IO and computation Operations
    Thread T-n takes more time to interact with external systems, does necessary steps and prepares Response-n and send it back to the Server
    Web Server in-turn send this Response-n to the Client-nIf “n” is greater than “m” (Most of the times, its true), then server assigns Threads to Client Requests up to available Threads. After all m Threads are utilized, then remaining Client’s Request should wait in the Queue until some of the busy Threads finish their Request-Processing Job and free to pick up next Request. If those threads are busy with Blocking IO Tasks (For example, interacting with Database, file system, JMS Queue, external services etc.) for longer time, then remaining clients should wait longer time.

  • Once Threads are free in Thread Pool and available for next tasks, Server pickup those threads and assign them to remaining Client Requests.
  • Each Thread utilizes many resources like memory etc. So before going those Threads from busy state to waiting state, they should release all acquired resources.

请求/响应无状态模型的缺点:

  • Handling more and more concurrent client’s request is bit tough.
  • When Concurrent client requests increases, then it should use more and more threads, finally they eat up more memory.
  • Sometimes, Client’s Request should wait for available threads to process their requests.
  • Wastes time in processing Blocking IO Tasks.

Node.js 架构 – 单线程事件循环

Node.js 平台不遵循请求/响应多线程状态模型,而是采用单线程事件循环模型。Node.js 的处理模型主要基于 JavaScript 的事件模型和回调机制。你应该对 JavaScript 事件和回调机制有一些良好的了解。如果你不了解,请先阅读这些文章或教程,并在进行下一步之前获得一些概念。由于 Node.js 遵循这种架构,因此它可以轻松处理越来越多的并发客户端请求。在讨论这个模型内部之前,请先参考下面的图表。我尝试设计这个图表来解释 Node.js 内部的每一点。Node.js 处理模型的核心是“事件循环”。如果我们理解了这一点,那么理解 Node.js 内部将非常容易。单线程事件循环模型的处理步骤如下:

  • Clients Send request to Web Server.
  • Node JS Web Server internally maintains a Limited Thread pool to provide services to the Client Requests.
  • Node JS Web Server receives those requests and places them into a Queue. It is known as “Event Queue”.
  • Node JS Web Server internally has a Component, known as “Event Loop”. Why it got this name is that it uses indefinite loop to receive requests and process them. (See some Java Pseudo code to understand this below).
  • Event Loop uses Single Thread only. It is main heart of Node JS Platform Processing Model.
  • Even Loop checks any Client Request is placed in Event Queue. If no, then wait for incoming requests for indefinitely.
  • If yes, then pick up one Client Request from Event QueueStarts process that Client Request
    If that Client Request Does Not requires any Blocking IO Operations, then process everything, prepare response and send it back to client.
    If that Client Request requires some Blocking IO Operations like interacting with Database, File System, External Services then it will follow different approach

    Checks Threads availability from Internal Thread Pool
    Picks up one Thread and assign this Client Request to that thread.
    That Thread is responsible for taking that request, process it, perform Blocking IO operations, prepare response and send it back to the Event Loop
    Event Loop in turn, sends that Response to the respective Client.

图表描述:

  • Here “n” number of Clients Send request to Web Server. Let us assume they are accessing our Web Application concurrently.
  • Let us assume, our Clients are Client-1, Client-2… and Client-n.
  • Web Server internally maintains a Limited Thread pool. Let us assume “m” number of Threads in Thread pool.
  • Node JS Web Server receives Client-1, Client-2… and Client-n Requests and places them in the Event Queue.
  • Node JS Even Loop Picks up those requests one by one.Even Loop pickups Client-1 Request-1

    Checks whether Client-1 Request-1 does require any Blocking IO Operations or takes more time for complex computation tasks.
    As this request is simple computation and Non-Blocking IO task, it does not require separate Thread to process it.
    Event Loop process all steps provided in that Client-1 Request-1 Operation (Here Operations means Java Script’s functions) and prepares Response-1
    Event Loop sends Response-1 to Client-1

    Even Loop pickups Client-2 Request-2

    Checks whether Client-2 Request-2does require any Blocking IO Operations or takes more time for complex computation tasks.
    As this request is simple computation and Non-Blocking IO task, it does not require separate Thread to process it.
    Event Loop process all steps provided in that Client-2 Request-2 Operation and prepares Response-2
    Event Loop sends Response-2 to Client-2

    Even Loop pickups Client-n Request-n

    Checks whether Client-n Request-n does require any Blocking IO Operations or takes more time for complex computation tasks.
    As this request is very complex computation or Blocking IO task, Even Loop does not process this request.
    Event Loop picks up Thread T-1 from Internal Thread pool and assigns this Client-n Request-n to Thread T-1
    Thread T-1 reads and process Request-n, perform necessary Blocking IO or Computation task, and finally prepares Response-n
    Thread T-1 sends this Response-n to Event Loop
    Event Loop in turn, sends this Response-n to Client-n

在这里,客户端请求是对一个或多个JavaScript函数的调用。JavaScript函数可能会调用其他函数,也可能利用其回调函数的特性。因此,每个客户端请求的样式如下所示:例如:

function1(function2,callback1);
function2(function3,callback2);
function3(input-params);

注意: –

  • If you don’t understand how these functions are executed, then I feel you are not familiar with Java Script Functions and Callback mechanism.
  • We should have some idea about Java Script functions and Callback mechanisms. Please go through some online tutorial before starting our Node JS Application development.

Node.js 架构 – 单线程事件循环的优势

    1. 处理越来越多的并发客户请求非常容易。

 

    1. 尽管我们的Node JS应用程序收到越来越多的并发客户请求,但由于事件循环,不需要创建越来越多的线程。

 

    Node JS应用程序使用较少的线程,以便只使用较少的资源或内存。

事件循环伪代码

作为一名Java开发者,我将尝试用Java术语解释“事件循环是如何工作的”。这不是纯粹的Java代码,我想每个人都能理解。如果你在理解上遇到任何问题,请给我留言。

public class EventLoop {
while(true){
        	if(Event Queue receives a JavaScript Function Call){
        		ClientRequest request = EventQueue.getClientRequest();
                            If(request requires BlokingIO or takes more computation time)
                                    Assign request to Thread T1
                            Else
                                  Process and Prepare response
                  }
            }
} 

这是有关Node JS架构和NodeJS单线程事件循环的全部内容。

发表回复 0

Your email address will not be published. Required fields are marked *


广告
将在 10 秒后关闭
bannerAds