Node.js开篇
记录了Node.js的组成与特点。
一、Node.js简介
Node.js是开源跨平台的JavaScript运行环境。基于chrome V8引擎、Libuv库及第三方模块实现的单线程应用。
其组成架构图如下图:
整体分为3个部分:
- Node.js 标准库:
这部分由 JavaScript 编写的 Node.js 核心模块,供使用者直接引用,位于源码的lib目录。 - Node Bingdings:
Node.js 程序的 main 函数入口,对底层模块进行封装为标准库提供C++类接口,是 JavaScript 与底层 C/C++ 沟通的桥梁,由 C++ 编写,位于源码的 src 目录。 - 最底层:
- V8 引擎: 用于解析、执行 JavaScrpit 代码的运行环境。
- libuv: 提供底层I/O操作接口,包括文件异步I/O线程池和网络的I/O操作,是整个异步I/O实现的核心,由 C/C++ 编写,位于源码的 deps 目录。
- 其他 C/C++ 组件和库:如 c-ares、http_parser 等,这些依赖提供了对系统底层功能的访问。
二、特点
1. 单线程
传统的 web 服务模型中,大多都使用多线程来解决并发问题。会为每个客户端连接创建一个新的线程,每个线程大约需要消耗2MB内存。理论上,一个8GB内存的服务器可以同时连接最大的用户数为4000个左右。Node.js只有一个主线程,当用户连接时会触发一个内部事件,通过非阻塞I/O、事件驱动机制,实现Node.js程序的并行,一个8GB内存的服务器,可以同时处理4万用户的连接。
优点:操作系统不再有线程创建、销毁的开销。
缺点:一个代码某个环节崩溃会导致整个系统的崩溃。
2. 非阻塞I/O
Node.js 采用了非阻塞I/O。例如,像是执行了访问数据库的代码后,将立即执行后面的代码,将数据库返回结果交由回调函数处理,从而提高了程序执行效率。当某个I/O执行完成后,将以事件的形式通知执行I/O操作的线程,线程执行这个事件的回调函数,为了处理异步I/O,线程必须有事件循环,不断的检查有没有未处理的事件,依次处理。
相反,阻塞模式下,一个线程只能处理一项任务,想要提高吞吐量必须通过多线程的方式。
3. 事件驱动
在Node.js中,客户端请求建立连接、调用接口等行为会触发相应的事件。
3.1 主线程
- main:启动入口文件,运行主函数。
- event pool:检查是否要进入事件循环。
- 检查其他线程里是否还有待处理事项。
- 检查其他任务是否还在进行中(比如计时器、文件读取操作等任务是否完成)。
- 有以上情况,进入事件循环,运行其他任务。 事件循环的过程:从timer 至 close callbacks整个流程走完,到event loop检查是否结束,没结束继续走一圈。
- over:所有事件都结束。
3.2 事件循环
三、Node.js适用场景
- I/O密集型场景
- RestFul API
- RPC 服务
- BBF
- Serverless
- 微服务