NodeJS架构:单线程事件循环模型

这篇译章探究了NodeJS的架构和单线程事件循环模型。我们将在本文中讨论“NodeJS如何在底层工作,它遵循什么类型的处理模型,NodeJS如何使用单线程模型处理并发请求”等内容。

NodeJS单线程事件循环模型

正如我们刚才说的,NodeJS使用的是“单线程事件循环模型”的架构去处理多个并发的客户端请求的。

有许多Web应用程序技术,如JSP,Spring MVC,ASP.NET等。但所有这些技术都遵循“多线程请求 - 响应”架构来处理多个并发客户端。

我们已经熟悉“多线程请求 - 响应”架构,因为它被大多数Web应用程序框架使用。 但是为什么NodeJS选择了不同的架构来开发Web应用程序。多线程和单线程事件循环体系结构之间的主要区别是什么?

NodeJS

NodeJS使用“单线程事件循环模型”架构来处理多个并发客户端。然而它是如何真正处理并发客户端请求且不使用多个线程。什么是事件循环模型?我们将逐一讨论这些概念。

在讨论“单线程事件循环”架构之前,首先我们将介绍著名的“多线程请求 - 响应”架构。

传统的Web应用处理模型

任何非NodeJS开发的Web应用程序通常都遵循“多线程请求 - 响应”模型。我们可以将此模型称为请求/响应模型。

客户端向服务器发送请求,然后服务器根据客户端请求进行一些处理,准备响应并将其发送回客户端。

该模型使用HTTP协议。由于HTTP是无状态协议,因此该请求/响应模型也是无状态模型。所以我们可以将其称为请求/响应无状态模型。

但是,此模型使用多线程来处理并发客户端请求。 在讨论这个模型内部之前,首先要看下面的内容。

请求/响应模型处理的步骤

客户端发送一个请求到Web服务器

Web服务器内部维护一个有限的线程池,以便在客户端请求提供服务

Web服务器处于无限循环中并等待客户端传入请求

Web服务器处理请求步骤:

接收到一个客户端请求

从线程池中选择一个线程

将此线程分配给客户端请求

此线程读取客户端请求,处理客户端请求,执行阻塞的IO操作(如果需要)和准备响应

此线程将准备好的请求发送回Web服务器

Web服务器又将此响应发送到相应的服务器

服务器为所有客户端执行以上步骤,为每一个客户端请求创建一个线程。

图表说明:

Client-1, Client-2, ..., Client-n是同时发送请求到Web服务器的客户端应用

Web服务器内部维护着一个有限的线程池,线程池中线程数量为m个

Web服务器逐个接收这些请求:

Web服务器拾取Client-1的请求Request-1,从线程池中拾取一个线程T-1并将此请求分配给线程T-1:

线程T-1读取Client-1的请求Request-1, 并处理该请求;

该请求无阻塞IO处理;

处理完必要的步骤后准备将Response-1发送回客户端;

Web服务器又将此Response-1发送到Client-1。

Web服务器拾取Client-2的请求Request-2,从线程池中拾取一个线程T-2并将此请求分配给线程T-2:

线程T-2读取Client-2的请求Request-2, 并处理该请求;

该请求无阻塞IO处理;

处理完必要的步骤后准备将Response-2发送回客户端;

Web服务器又将此Response-2发送到Client-2。

Web服务器拾取Client-n的请求Request-n,从线程池中拾取一个线程T-n并将此请求分配给线程T-n:

线程T-n读取Client-n的请求Request-n, 并处理该请求;

Request-n需要大量的阻塞IO和计算操作;

线程T-n需要更多时间与外部系统(SQL, File System)交互,执行必要步骤并准备Response-n并将其发送回服务器;

Web服务器又将此Response-n发送到Client-n。

如果'n'大于'm'(大多数时候,它是真的),则在使用完所有的m个线程之后,剩余的客户端请求会在队列中等待。

如果这些线程中有大量的阻塞IO操作(例如:和数据库、文件系统、外部服务等交互),那么剩余的客户端也会等待更长的时间。

一旦线程池中的线程空闲且可用于下一个任务,服务器就会拾取这些线程并将它们分配给剩余的客户端请求。

每个线程都会使用到许多资源,如内存等。因此,在将这些线程从忙状态转到等待状态之前,它们应该释放所有获取的资源。

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

在处理越来越多的并发客户端请求时会变得棘手

当客户端请求增加时,线程也会越来越多,最后它们会占用更多内存。

客户端可能需要等待服务器释放可用的线程去处理其请求

处理阻塞式的IO任务时浪费时间

NodeJS架构:单线程事件循环

NodeJS不遵循请求/响应多线程无状态模型。 它采用单线程与事件循环模型。 NodeJS的处理模型主要基于Javascript基于事件的模型和Javascript回调机制。

因为NodeJS遵循的架构,它可以非常轻松地处理越来越多的并发客户端请求。 在讨论这个模型内部之前,首先要看下面的图表。

我试图设计这个图来解释NodeJS内部的每一点。

NodeJS的处理模型主要核心是“事件循环(Event Loop)”。如果我们理解这一点,那么很容易理解NodeJS的内部架构的。

单线程事件循环模型的处理步骤

客户端发送请求到Web服务器

NodeJS的Web服务器在内部维护一个有限的线程池,以便为客户端请求提供服务

NodeJS的Web服务器接收这些请求并将它们放入队列中。 它被称为“事件队列”

NodeJS的Web服务器内部有一个组件,称为“事件循环”,它使用无限循环来接收请求并处理它们。

事件循环只使用到了一个线程,它是NodeJS的处理模型的核心

事件循环回去检查是否有客户端的请求被放置在事件队列中。如果没有,会一直等待事件队列中存在请求。

如果有,则会从事件队列中拾取一个客户端请求:

开始处理客户端请求

如果该客户端请求不需要任何阻塞IO操作,则处理所有内容,准备响应并将其发送回客户端

如果该客户端请求需要一些阻塞IO操作,例如与数据库,文件系统,外部服务交互,那么它将遵循不同的方法:

从内部线程池检查线程可用性

获取一个线程并将此客户端请求分配给该线程

该线程负责接收该请求,处理该请求,执行阻塞IO操作,准备响应并将其发送回事件循环

事件循环依次将响应发送到相应的客户端

图表说明:

Client-1, Client-2, ..., Client-n是同时发送请求到Web服务器的客户端应用

Web服务器内部维护着一个有限的线程池,线程池中线程数量为m个

NodeJS的Web服务器接收到Client-1, Client-2, ..., Client-n的请求后,将请求放入到事件队列中

NodeJS的事件循环从队列中开始拾取这些请求:

事件循环拾取Client-1的请求Request-1

检查Client-1 Request-1是否确实需要任何阻塞IO操作,或者需要更多时间来执行复杂的计算任务

由于此请求是简单计算和非阻塞IO任务,因此不需要单独的线程来处理它

事件循环处理该请求所需要的操作,准备其响应Response-1

事件循环发送Response-1到Client-1

事件循环拾取Client-2的请求Request-2

检查Client-2 Request-2是否需要任何阻塞IO操作或花费更多时间来执行复杂的计算任务

由于此请求是简单计算和非阻塞IO任务,因此不需要单独的线程来处理它

事件循环处理该请求所需要的操作,准备其响应Response-2

事件循环发送Response-2到Client-2

事件循环拾取Client-n的请求Request-n

检查Client-n Request-n是否需要任何阻塞IO操作或花费更多时间来执行复杂的计算任务

由于此请求有非常复杂的计算或阻塞IO任务,因此事件循环不会处理此请求

事件循环从内部线程池中获取线程T-1,并将此Client-n Request-n分配给线程T-1

线程T-1读取并处理Request-n,执行必要的阻塞IO或计算任务,最后准备响应Response-n

线程T-1将此Response-n发送到事件循环

事件循环依次将此Response-n发送到Client-n

此处客户端请求是对一个或多个JavaScript函数的调用,因为JavaScript函数可以调用其他函数或可以利用其回调函数性质。

此所以每个客户端的请求处理都看起来向这样:

例如:

1function1(function2,callback1);

2function2(function3,callback2);

3function3(input-params);

NodeJS的单线程事件循环的优势

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

因为事件循环的存在,即使我们的NodeJS应用接收到了越来越多的并发请求,我们也不需要去新建很多的线程

NodeJS使用到了较少的线程,所以资源和内存的使用较少

顺便给大家推荐一个裙,它的前面是 537,中间是631,最后就是 707。想要学习前端的小伙伴可以加入我们一起学习,互相帮助。群里每天晚上都有大神免费直播上课,如果不是想学习的小伙伴就不要加啦。

*  作者:RAMBABU POSA

*  原文地址:https://www.journaldev.com/7462/node-js-architecture-single-threaded-event-loop

*  声明:转载文章和图片均来自公开网络,版权归作者本人所有。如果出处有误或侵犯到原作者权益,请与我们联系删除或授权事宜。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容

  • 昨天中午午睡后,起床,脑子里突然闪出一个念头:要是我现在就死过去了?会怎么办?当这个念头一出来,眼睛就惶恐的扫...
    明波1阅读 402评论 0 1
  • 温暖。 是我最喜欢的词儿之一。 从毕业一路走到现在,我很幸运的结识了很多好朋友,不在乎对方身世,不关心对方阶层的好...
    饕餮思文阅读 517评论 4 2
  • 1.变量原子性引发的问题 这里我们通过一个很经典的案例i++来分析下原子性问题 执行完i++后为什么结果是10,原...
    匆匆岁月阅读 314评论 0 0
  • 还记得吗?7.4那天,下午三点半我给你打了两次电话,你没接。四点钟你回了过来,问我是不是有事,才一定要打电话...
    双鱼的天蝎阅读 229评论 0 1