NodeJS就是癌症[2011]


发布者 ourjs  发布时间 1416537046308
关键字 我要吐嘈  瞎扯 
注* 此文为2011年发表的一篇老文,作者为Tedd,原先发表于其博客,己被删除。这里是HackNews上的评论,以及现存的英文原文,表现了一部分程序员对两种(异步,同步)不同编程方式的喜好。

要成为所有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 创始人)也感到羞愧
}

还有更多,我什么也不说了……


最后


Node.JS不是个好软件,我不会用它。










回复 (9)
  • #
  • #1 吕尘寺 1416791799584

    擦,完全是瞎扯淡

  • #2 时永出 1416794897331

    觉得瞎扯淡的能否给出理由给予反驳?

  • #3 jackong 1416796176125

    任何语言 用对了地方 都是好语言 用对了人 才是好程序员

  • #4 小猫咪 1416810848828

    有点偏激呀喵

  • #5 pockry 1416878006183

    第一条,呵呵。 第二条,呵呵。 第三条,呵呵。

    总结:呵呵。

  • #6 吕力导 1417058404545

    菜鸟

  • #7 Redstone 1417398599842

    怀着挑刺的心态,任何语言都深入了解后都能列出那么几条缺点。

  • #8 严观汇 1425027698435

    看你付出和回报的比例把。语言和软件只是工具而以。重要的事你用他们弄出来的产品怎么杨????如果你付出了很多精力去学习新的语言,框架。新的库。到头来发现在你的项目中用途不大。就真是浪费时间。我是实用主义者。

  • #9 危因亦 1435539958261

    没人逼你用啊

微信扫码 立即评论