nodejs在服务器端编能够处理大链接的原因到底是什么?
发布于 12 年前 作者 cloudaice 10082 次浏览 最后一次编辑是 8 年前

读完那本入门的nodejs书,也把例子写了一下,之前javascript只会一点点。不过会python,对于函数回调这些虽不能说完全理解,但是也明白意思。写完那些例子之后,有一下几点感觉:

用nodejs写web应用,要自己考虑不同url请求之间的阻塞和非阻塞问题。因为用nodejs写完一个应用,就相当于也写完了一个web服务器。

总感觉,代码可读性不时那么好,尤其可能在回调函数这些比较复杂的情况下。而且感觉写同样的 一个应用,写的代码量还是比较多的(相对于python而言)。

对于它为什么能够处理高并发不是很明白,首先,我听到别人说的原因是它是单线程的,减少了上下文,切换时间,同时减少了内存的使用。表面看上去这个说法挺有道理,但是仔细一样,感觉不太对。既然单线程可以胜任,web服务器的功能,那么之前的web服务器怎么没有设计成单线程呢?至少解释不够透彻。其次,在看那本入门的书的时候,说道非阻塞的问题。说是使用轮询,这里指的轮询是在线程上的轮询吗?后来看到说道IO操作其实也是使用了多线程。具体也没怎么看明白。反正,感觉疑惑挺多的。

11 回复

真正看明白了也就是那样。

记得之前看过篇文章讲这个原因,其实nginx也和node.js类似,都用了单线程,这样避免个了大量并发时产生过多的进程和线程拖慢系统。进程和线程拖慢系统的主要原因在于切换代价和额外的重复内存开销,但是使用多进程的话稳定性会更高。apache里面有点小bug影响的只是当前出状况的连接,但是node.js出状况那么整个webserver都瘫了。

非阻塞IO是让单线程可以顺畅跑起来的关键,apache其实也支持非阻塞模式的,只是意义不大,因为本来多进程的情况下也就是阻塞了自己一个进程罢了,其他进程还是并行再跑的。

轮询是事件循环层次上的。

最关键的是io的多线程和并发,这个肯定是系统重要瓶颈,据说node.js依赖的libeio默认情况下也没让io并行起来。或者这么说吧,io这个东西主要就是串行的,所以凡是依赖io的,肯定快不了,无论你是用多线程去io还是单线程io,对缓解大并发没有太多实际作用。

另外一个快是v8的速度比较快。其实和nginx比起来,主要是因为javascript这个东西比较好,让前后端开发更趋一致。真要拼极致性能,估计还是要上cgi什么的吧。

总体而言,扛住大并发的核心原因是单线程降低上下文切换的开销和内存开销。其他那些号称的特性都是为了实现这一点而存在的。

补充一下。我认为真要扛住高访问量,不能依赖webserver这个层次的优化。必须在webserver前的负载均衡和反响代理要处理好。webserver性能差些关系不大,反倒是尽量少依赖session,让负载均衡可以随意跳webserver反而可以提升整个系统性能,用户体验更佳。 就拿北京伦敦奥运门票和春节铁道部的情况来说,最后死在两个地方,数据库间同步和负载均衡设备吞吐量。没啥网站是被webserver性能拖垮的

准确的说,是能 ”很快的接入大量的并发I/O并进行排队“ ,其实就是把等待I/O完成的时间巧妙的 ”让出来“ (异步回调机制)去接收更多的请求,只不过 js 有闭包,语言实现上更方便自然而已。

apache等待io的时间本来也没浪费,也用来开新进程了。apache最后是被内存和上下文切换拖死,并没有等死在io上。

单线程的非阻塞io具体是怎么实现的?它如何保证io结束后,就会去执行。是轮询吗?轮询的话,那么就需要排队。要是io很多的话,这个queue也会很长,而且也会在轮询上浪费很多时间,其实就像是做了OS的调度的事情。另外,仅仅单线程,那对多核处理器是如何支持呢? 的确一个网站大多都是被io托跨的,所以经常会听到大量用cache。还有google的什么bigtable之类的。

@rabby 那肯定的啊,断然不能让时间花在等待一个IO上。那也就是说,node是在线程级上面,进行模仿了OS的多线程,进程调度。但是节省了OS里的上下文切换时间。

随便说两句, 真正限制并发的是硬件的资源,带宽,硬盘, cpu,内存等IO, 其中硬盘IO是目前最大的瓶颈,而且无法调度优先级, 不同的webserver 只能掌控CPU 和内存的管理, 基于事件设计的webserver(nginx,nodejs)能够在并发持续增长的情况下,有效控制内存的占用,这在内存不够的服务器上就特别明显,所以即使是大并发,事件式的webserver依然照收不误,不会拖垮服务器,依然能够处理访问,不过访问的回应还是要等硬盘IO结束了才行。

这是webserver层面的, 还有个nodejs独有的优势是 应用层nodejs VS PHP。

nginx + php-fpm是最常见的php web应用的架构,这种明显缺点是一个访问必须有一个php进程来接受,而php是阻塞式的,其本身语言的设计也很有缺陷,无法共享资源,一个周期执行一次释放一次,所以就产生了类似c/java做的数据库连接池,来为php服务。

nodejs + js webserver直接加载代码的形式,又基于非阻塞异步式的,对内存的控制相当优异,资源间的共享应该是可以的,nodejs mysql模块里就有 连接池功能的模块,由此可见语言应用层面,也胜PHP很多。

io结束后提交结束事件,然后等到事件队列处理到你这个事件的时候再执行。也不是马上执行,只不过不涉及到io的代码一般运行速度都很快,和io消耗的时间比起来就像是立即执行了一样。

因为是单线程,所以多核用不上。想要利用多核就需要自己起多个node.js进程,分派给不同的cpu,然后再用一个反向代理什么的的来负载均衡。

老实说新出的apache2.4也正式吸收了这些事件和异步的执行方式,内存开销上也大大改善,性能并不比nginx和node.js差了。

所以现在node.js在性能什么的上面已经不是主要特色了,主要特色转到小巧和js语言特性上了。

多谢各位解释,受益匪浅!!!

回到顶部