读完那本入门的nodejs书,也把例子写了一下,之前javascript只会一点点。不过会python,对于函数回调这些虽不能说完全理解,但是也明白意思。写完那些例子之后,有一下几点感觉:
用nodejs写web应用,要自己考虑不同url请求之间的阻塞和非阻塞问题。因为用nodejs写完一个应用,就相当于也写完了一个web服务器。
总感觉,代码可读性不时那么好,尤其可能在回调函数这些比较复杂的情况下。而且感觉写同样的 一个应用,写的代码量还是比较多的(相对于python而言)。
对于它为什么能够处理高并发不是很明白,首先,我听到别人说的原因是它是单线程的,减少了上下文,切换时间,同时减少了内存的使用。表面看上去这个说法挺有道理,但是仔细一样,感觉不太对。既然单线程可以胜任,web服务器的功能,那么之前的web服务器怎么没有设计成单线程呢?至少解释不够透彻。其次,在看那本入门的书的时候,说道非阻塞的问题。说是使用轮询,这里指的轮询是在线程上的轮询吗?后来看到说道IO操作其实也是使用了多线程。具体也没怎么看明白。反正,感觉疑惑挺多的。
记得之前看过篇文章讲这个原因,其实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性能拖垮的
单线程的非阻塞io具体是怎么实现的?它如何保证io结束后,就会去执行。是轮询吗?轮询的话,那么就需要排队。要是io很多的话,这个queue也会很长,而且也会在轮询上浪费很多时间,其实就像是做了OS的调度的事情。另外,仅仅单线程,那对多核处理器是如何支持呢? 的确一个网站大多都是被io托跨的,所以经常会听到大量用cache。还有google的什么bigtable之类的。
随便说两句, 真正限制并发的是硬件的资源,带宽,硬盘, 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很多。