要成为所有Web开发都都喜爱的事情,就需要做得比传统的方法更好,但传统之所以成为经典的一个原因就是:最终的产品。关于Node.js一直困扰着我,我觉得它豪无意义,但我从来没有时间说明原因,直到我读了Ryan Dahl的文章(注*己被删除),NodeJS的创造者之一。我要耸耸肩,把它当成傻瓜一样抱怨,因为它像Unix一样难。但是,就像一名警察预感到面包车里藏着50公斤的海洛因一样,我觉得事情不太对,也许,只是也许,人们并不知道自己在做什么,尽管他们已经写了很多年代码。
既然你读到这里,你可能已经知道我的想法了。
Node.js的是编程社区的肿瘤,它不仅是没有脑子,而且它也会感染其他人,不让他们自我思考,直到最后,每一个我碰到的混蛋都想告诉我,事件循环的优越性。你内心有没有接受这种想法?
扩展性是正在酝酿的肿瘤
让我们先看看最可怕的谎言:Node.js是可扩展的,因为它“永远不会被阻塞”(辐射对你是有好处的,我们会在你牙膏里放一点!)。在Node的主页,他们这样说:
几乎任何Node函数会不会直接执行I/O操作, 所以整个过程不会阻塞。因为没有阻塞,一般的的程序员也能写出极快的系统。
这种说法是诱人的,令人欣喜的,但完全是他妈的错的。
让我们先从看看一些场景。拿函数调用来说,当执行此函数时当前线程会等到该功能结束,然后再继续下一个操作。通常情况下,我们认为I/O是“阻塞”的,比如你在调用socket.read(),程序会等待该调用完成后继续,因为你需要它的返回值。
这里有一个有趣的现象:每个函数的调用,在CPU里也是阻塞的。比如此功能,它计算的第n个Fibonacci数(斐波那契数列),将被阻塞CPU当前的执行线程。
function fibonacci(n) {
if (n < 2)
return 1;
else
return fibonacci(n-2) + fibonacci(n-1);
}
让我们看看node.js程序,这个小天才是怎么处理请求的:
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(fibonacci(40));
}).listen(1337, "127.0.0.1");
在我的老式笔记本上,它的结果是这样的:
ted@lorenz:~$ time curl http://localhost:1337/
165580141
real0m5.676s
user0m0.010s
sys0m0.000s
5秒的响应时间。太酷了!而且,大家都知道JavaScript是非常快的一种语言,但为什么会这样?这是因为node的事件模型和脑损伤的粉丝们让你觉得这一切都还好。在这真的是在辱骂代码,这是事件循环(Event Loop)的工作原理(伪代码):
while(1) {
ready_file_descriptor = event_library->poll();
handle_request(ready_file_descriptor);
}
这一切都很好,只要你知道你在做什么。当你将这个服务部署到服务器上就会出问题,你会碰到狗屎一样的事。因为这个循环在同一个线程运行handle_request,任何程序员会都发现,请求处理程序会阻塞整个事件循环,无论你的库有多么异步。
所以,鉴于此,让我们来看看我的小node服务器在最温和负载情况下的表现,在10个请求,5个并发的情况下:
ted@lorenz:~$ ab -n 10 -c 5 http://localhost:1337/
...
Requests per second: 0.17 [#/sec] (mean)
...
0.17个请求/秒。当然,Node可以派生(fork)的子进程,但在这一点上你的线程/事件模型结合的如此紧密,你会遭遇扩展性上更大的问题。
考虑到Node的最初的卖点,上帝被这种“极快的系统”吓坏了,即“一般程序员”给这个世界带来的东西。
Node惩罚了开发者因为它违背了Unix的原则
很久很久以前,最初neckbeards的设计是非常好的,每条链上执行特定的任务,以及它们之间的通用接口应该仅仅是文字。
当你在Unix平台上开发,你遵守这个原则,操作系统会回报给你简单和稳定。这里有一个例子,当Web应用程序第一次运行时,Web应用程序只是将标准印刷文本到输出的程序。 Web服务器负责获取传入请求,执行该程序,并返回结果给请求者。我们称这个为CGI,这是一个很好的做生意的方式,直到你那肮脏的双手将徽优化放进去。
从概念上讲,这是任何没有癌症的Web应用程序仍然有效的工作方式;你的Web服务器程序的工作就是接受传入的请求,解析它们,并找出相应采取的措施。这可以服务于一个静态文件,运行CGI脚本,进行连接到别的地方的代理,等等。关键的一点是,HTTP服务器在不同实体内的应用程序工作。开发者使用阻塞将各个调用任务分离,它的存在是有原因的:松耦合架构非常易于维护。
然而,node似乎无视这一点。Node(不要笑,这陀屎不是我做的)自己的HTTP服务器,应该使用上面的http.createServer(这个例子)的设置,以满足生产环境的流量。
如果你搜索“Node.js部署”,你会发现一堆人把Nginx放在Node前端,他们称之为称为Fugue(反向代理?),这是派生出一堆进程来处理传入的请求到另一个JavaScript HTTP服务器,仿佛有人也许认为这种“非阻塞”是万金油,不过可能会有另外一个问题,CPU性能的限制。
注* 此处作者理解有误,Nginx是由C语言写的,用异步非阻塞模型实现的,进程数量(worker)是固定的,而非一堆进程,相关文章:NodeJS on Nginx: 使用nginx反向代理处理静态页面, Nginx的大计划:将原生支持JavaScript;
如果您使用Node,99%的概率你即是开发人员和系统管理员,因为任何系统管理员会说服你首先使用Node。所以,你这个开发者,必须把一个真正的Web服务器当成静态文件服务来弄,查询重写,速率限制,负载均衡,SSL,或任何现代HTTP代理服务器应该做的那样。保证系统的健康稳定运行。
不过,说句实话,如果你是一个Node的开发者,你可能直接使用Node提供网络服务,直接在您的命令行启动。
扯蛋的JavaScript
这也许是服务器端程序能做到的最差的一件事:使用JavaScript写代码
if (typeof my_var !== "undefined" && my_var !== null) {
//你的白痴让Rasmus Lerdorf(php 创始人)也感到羞愧
}
还有更多,我什么也不说了……
擦,完全是瞎扯淡
觉得瞎扯淡的能否给出理由给予反驳?
任何语言 用对了地方 都是好语言 用对了人 才是好程序员
有点偏激呀喵
第一条,呵呵。 第二条,呵呵。 第三条,呵呵。
总结:呵呵。
菜鸟
怀着挑刺的心态,任何语言都深入了解后都能列出那么几条缺点。
看你付出和回报的比例把。语言和软件只是工具而以。重要的事你用他们弄出来的产品怎么杨????如果你付出了很多精力去学习新的语言,框架。新的库。到头来发现在你的项目中用途不大。就真是浪费时间。我是实用主义者。
没人逼你用啊