本文主要讨论以下问题:
1.Node.js 的事件驱动模型分析
2.Node.js 如何处理高并发请求?
3.Node.js 的缺点介绍
先简单介绍一下 Node.js,Node.js 是基于事件驱动、非阻塞 I/O 模型的服务器端 JavaScript 运行环境,是基于 Google 的 V8 引擎在服务器端运行的单线程、高性能的 JavaScript 语言。
一、Node.js 事件驱动模型分析
看懂上图之后,你就明白 Node.js 的事件驱动模型了,从上图中我们可以看到以下几个部分:
Application 应用层,也就是 JavaScript 交互层,是 Node.js 的常用模块,比如 http,fs 等。
V8 是 V8 引擎层,主要用于解析 JavaScript,与应用层和 NodeApi 层交互。
NodeApi 为上层模块提供系统调用,并与操作系统交互。
Libuv 是一个跨平台的底层包,实现了线程池、事件循环、文件操作等。实现异步是 Node.js 的核心。
Libuv 层维护一个事件队列的事件队列。当请求到来时,Node.js 的应用层和 NodeApi 层将请求作为事件放入事件队列,设置回调事件函数,然后继续接受新的请求。
在 Libuv 层的 Event Loop 事件循环中,事件队列中的事件被连续读取。在读取事件的过程中,如果遇到非阻塞事件,就自己处理,处理完后调用回调函数将结果返回给下一层。对于阻塞事件,会委托给后台线程池来处理。当这些阻塞操作完成后,执行结果将和提供的回调函数一起放入事件队列。当事件循环再次读取该事件时,将再次执行放置在队列中的事件回调函数,最后将结果返回给上级。详情请参考下图:
二、Node.js 如何处理高并发请求?
如果你理解了最后一个问题,就好理解了。如果要总结的话,就是异步无阻塞编程的思想。当遇到耗时的操作时,会以异步非阻塞的方式进入事件队列,不会影响后续请求的执行。循环将读取这个耗时的请求,并将其交给线程池进行处理。当这些耗时的操作被处理后,会再次进入事件队列,请求结果通过事件循环和回调返回给上层应用,最终返回给客户端。以上方式减少了高并发的等待时间,让高并发可以从容应对。
三、Node.js 的缺点介绍
通过上面的介绍,我们知道了 Node.js 的事件驱动模型,下面我们将介绍 Node.js 的不足之处。
Node.js 最大的缺点是一次只能服务一个请求。目前大部分服务器都是多核 CPU,导致 CPU 利用率非常低,资源浪费。
Node.js 的主线程 Event Loop 按照事件队列的顺序执行事件队列中的事件。在其中一个任务完成之前,回调和监听器等其他函数都没有机会运行,因为被阻塞的事件循环没有机会处理它们。如果发生这种情况,程序执行速度将会变慢。点此下载完整附件