NodeJs是一种用JavaScript编写,运行在Google V8引擎的服务端程序,在2009年出来,在经历过几个版本后,现在已经被运用在某些特定的地方,比如网站前后端分离,聊天室等。
在看NodeJS的一些介绍的时候,经常会看到高并发和高性能两个词,这里看一下为什么会高并发和高性能:
1. NodeJS对于一个请求,不再是创建一个线程,所以这就减少了创建线程带来的性能损耗,性能就可以上去,同时也避免了OS底层对进程内线程数的限制,并发就可以上去。
2. NodeJS内部是基于事件循环的,而且是基于异步IO的,所以避免了CPU的上下文切换,同样解决的系能损耗,
但是这里要注意一个问题:
1. NodeJS进程并不是真正意义的单线程,比如一个NodeJS请求,要进行网络访问,并将相应内容写入到磁盘,其实是有3个IO线程,1是一个http请求的IO线程,一个是网络访问的IO线程,还有一个是磁盘IO线程。 NodeJS的线程模型可以理解为一个工作线程,多个IO线程。
下面是NodeJs的结构图:
其中Libuv是一个适配层,主要针对*nix和Windows下异步IO的适配,进程间通信的适配。
看NodeJs的介绍,经常看到的就是异步, 这里的异步本质就是操作系统的异步,所以这里理解了操作系统的异步,也就理解了NodeJS的异步,关于同步,异步,阻塞和非阻塞,可以参考 http://bbym010.iteye.com/blog/2100868
关于异步可以参考下面这种图:
这个特性是在0.6版本以后才被加入进行的, 是为了解决NodeJS服务器资源利用率不高的问题,其解决方案就是有一个Maste进程,在启动的时候,再fork()多个work进程,Master监听主端口(比如80),在接受到一个请求后,就会有一个链接句柄,把这个链接句柄发送到Work进程去。
这里面牵扯到进程间的通信,这个通信针对不同的操作系统进行了封装,如下:
虽然NodeJs现在被运的地方很多,但是也还是有一些问题
-
逻辑编写麻烦:NodeJS的程序是基于异步回调的, 所以在编写代码的时候, 会有大量的回调代码,这一点对于那些习惯编写“顺序”代码的程序员有不小的影响。这个相比.Net程序还是有差距(.Net程序可以以同步的方式写异步代码),目前我查了资料,已经存在一些将异步转为同步的解决方法,还有一种解决方法就是修改语法,以同步的方式编写代码,然后修改编译器或者运行时,将同步转为异步模式运行。
-
单线程:NodeJS的运行时只有一条线程,基于事件循环来处理,这造成了两个问题:
-
现在的服务器都是多核心的,而 NodeJS只运行在单核上,不可避免的对服务器的资源造成一定的浪费。
-
对IO密集型友好,对CPU密集型不友好,虽然NodeJS底层是基于V8的,性能很高,但是因为是单线程,稍微复杂的逻辑判断就有可能阻塞事件循环。
-
目前NodeJS自身已经提出了解决方案,就是Cluster,本质就是父子进程的概念,由一个Master进程启动多个Work进程,进程数和CPU核心相关,所有的请求经过Master进程,然后再分配到具体的Work线程,这个模型和Nginx的模型类似, Cluster模型可以解决资源被浪费的情况, 也能从一定程度上缓解CPU的问题,但是和传统的Apache比起来,还有一定差距。
本篇博客部分图片来自 《深入浅出Node.js》