前言
本综述文章旨在帮助读者深入理解下Node.js的本质,不去关注应用的细节,我认为真正的技术问题只有在动手写代码的时候才会遇到,那个阶段解决问题才是真正有意义的。
发展史
Node.js是Ryan Dahl 2009年对外发布的开源醒目,后来该项目被Joyent公司注意到并于2010年成为Joyent公司的一个子项目。2016年微软与Joyent公司合作,Node.js在windows上得到支持。
目前Node.js的版本为V6.11,周围已经形成了一个庞大的生态系统。
特性分析
Node.js is a JavaScript runtime built on Chrome‘s V8 JavaScript engine. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient. Node.js‘ package ecosystem, npm, is the largest ecosystem of open source libraries in the world.
上面是Node.js的官方描述,其中包含了Node.js最突出的特点。
1、Javascript runtime
这个描述解答了Node.js是什么的问题。它是一个Javascript 运行环境,类似于JVM之于Java,Node.js负责将Javascript转化为计算机可以识别的机器语言,同时对外提供API。传统上javascript依附于浏览器运行:
Node.js舍弃了浏览器,直接与js引擎对接,通过js引擎提供的API,Node.js可以完成其他后端语言(java)所能完成的一切功能,例如文件操作、网络通信、设备管理等等。
下面说下Node.js所采用的js引擎——V8,这是目前世界上最快的js引擎,来自于Google Chrome项目,用C++语言编写,凭借Goole强大的技术支持,它的执行速度已经接近本地代码的执行速度。
除了V8以外,Node.js的还是用了libev和libio库支持事件驱动和异步IO,如图所示,libuv是在libev和libeio的基础上抽象出的一层,对于POSIX系统,libuv利用epoll或者kqueue,而在Windows系统中,libuv使用了IOCP机制,以在不同的平台下实现统一的高性能。
2、non-blocking IO and event-driven
先说说非阻塞IO,假设一个请求要读取数据库,db.query(select * from table),这个过程涉及磁盘读取与网络通信,耗时很长,下面是几种服务器处理方式。
(1)如果是单线程+阻塞处理,前端会等待数据读取完毕才接受到消息,同时后续的请求也得等待,这样的系统是不能忍受的。
(2)好在现在的后端容器都是支持多线程+阻塞的,其解决思路如下:
等待数据的现场继续等待,如果有新请求就重新创建一个线程,把cpu让给新的线程,待原线程得到数据后再把cpu切换给原线程。这样做有什么缺点么?
一是大量请求的情况下线程数目不断增加,浪费大量系统资源。
二是CPU在处理上下文切换的时候也浪费了不少时间。
(3)Node.js的解决思路则完全不一样。它被设计成单线程+非阻塞的。
所有的请求都在一个线程处理,一旦遇到耗时的请求,cpu不等待数据返回,而是接着处理后续的请求。那么问题来了,前面请求的数据到达后,如何返回给前端呢?这就要牵扯到Node.js的另外一个特性——事件驱动。
在上面的简化模型中,所有的请求会依次进入线程的处理循环中,每个请求自带回调函数,当耗时请求接受完数据后,回调函数自动被调用,重新进去循环处理,直到数据被返回给前端。
这样能让单个CPU充分运行起来,没有丝毫等待,同时避免了在不同的线程中频繁切换引起的浪费。根据统计,Node.js相对传统的PHP+Nginx,在性能上有明显提升。
这种设计思路就是为微服务web系统而生的,因为web服务的特点就是请求密集、计算量小、要求快速响应。
Node.js的缺点
1、对于长期占据CPU的请求,后续的请求不能得到及时处理,产生较大延时,所以Node.js不适合计算密集型应用。
2、Node.js专注单线程处理,在多核环境中,必须总多进城才能充分利用多核,因此增加了设计难度。
3、Node.js的异步式编程模式不太符合一般的程序控制思路,给编码和调试带来不少困难。
常用辅助框架
1、npm(Node Package Manager)
Node.js本身提供的API比较底层,完全依靠Node.js实现一个系统对技术人员要求比较高。不过现在已经有大量的第三方支持供开发者使用。为了更好地使用和管理这些第三方提供的包,Node.js官方提供了一个基于命令行的包管理工具——npm.
npm完全由javascript实现,不属于Node.js的一部分。不过在Node.js0.6开始,npm会自动包含在发行版中。
2、Express
参考
《Node.js开发指南》