首页 > IT资讯 > 正文

Node.js真的无所不能?那些不适用的应用领域分析

Node.js是一个服务器端JavaScript解释器,底层采用的还是libevent;它的目标是帮助程序员构建高度可伸缩的应用程序,目前对Node.js 的采用状况,Node.js 官方站点有一些罗列,但是相当不完整。如果你自己公司用到,也可以在 github 上提交自己的 pull-request 来更新这个文档。

http://nodejs.org/industry/

https://github.com/joyent/node/wiki/Projects,-Applications,-and-Companies-Using-Node

其实到今天为止,很少有哪些大的互联网公司是和 Node.js 无关的。LinkedIn,Yahho,Paypal, eBay, Walmart 都在将既有的系统向 Node.js 迁移(https://www.quora.com/Node-js/What-companies-are-using-Node-js-in-production 翻墙看)。国内的淘宝、网易、百度等也都有很多项目运行在 Node.js 之上。

2011 年我开始接触 Node.js 的时候,npmjs.org 上只有不到 3,000 个 Node.js 的 packages,今天(2014-3-2)则有 61,897 个,这个数字还在快速增长中。

下面有两个链接,第一个是在讲 Walmart 这几年为什么以及如何迁移到 Node.js 上;第二个则为 eBay 是如何从 Node.js 的怀疑者转变为采用者。

Node.js at Walmart

eBay's Node.js Adoption Journey

《Announcing ql.io》 这篇文章的最后一段,列出了 eBay 为什么选择 Node.js。

每天都有几百个新的 packages 被发布到 npm 上,小到几行代码,大到万行代码的 Framework。一天有7百万次的包下载(安装到某台电脑上),对于单一开发框架的社区来说,用沸腾的海洋来形容并不过分。

 

以下应用领域和程序员不适合选择Node.js:

计算密集型应用。Javascript 的计算性能是很难和 C 语言代码相比的。当然,也有反例:http://onlinevillage.blogspot.jp/2011/03/is-javascript-is-faster-than-c.html,只不过不具有典型性。

需要精密控制内存的分配和释放的场景,如果用 Node.js 实现 Redis 数据库,虽然程序会简单不少,但是 JVM 对内存数据结构的精密控制能力是比不了用 C 语言纯手工打造的。

大量且需要频繁通过 C Binding 调用 C library 的情况。这种场景下,往返参数的 Marshal/Unmarshal 的成本可能会大于 C Library 带来的性能提升。

实时性要求很高的场景,例如:交换机或者工控机器人。这是因为所有通过垃圾回收机制来管理内存的系统都有可能在 GC 过程中产生停顿,从而影响响应速度,而且很难优化。

需要单一进程控制大内存的场景:v8 引擎的设计限制,在 32-bit下有 1GB 最大堆尺寸的限制,在 64-bit下是1.7GB。当然,由于 node.js buffer 的分配不是在 v8 的堆上,因此可以超过此限制。这个限制可以通过向 v8 引擎传递max_old_space_size 参数来超越,但是也会带来 GC 的性能退化。这一问题在几乎所有 GC Based 的系统下都存在。

不关心系统吞吐率或者不需要异步调用的场景:例如,自动化脚本,这些脚本不需要关心多用户并发访问的性能消耗。用 Python 这样的“胶水”语言写起来会更简单。

某些非通用场景:例如 nginx 对于静态 web server 或者 反向代理的场景是特别设计的,这些场景中 nginx 的性能比 Node.js 要好。

强类型强迫症:有些 Java 或者 .NET 过来的程序员会认为只有强类型语言和严格定义的类型系统是专业化的象征,构造这样的系统是架构师的使命,而动态语言只是玩具,只能用来做 Demo 或者前端开发。

团队成员难以理解或者接受函数式编程:Javascript 本质上更像函数式语言,有些程序员在理解和使用闭包、高阶函数等概念时总是不能习惯,这个问题在国内的开发团队中还挺普遍的。

回调式编程的不习惯:Node.js 的异步IO 大量依赖回调。回调让程序的执行出现了两条路径,出现故障时调用栈也很难理解。这对习惯了同步编程的程序员来说一开始确实是个坎。async, Q promise 等 package 可以缓解这个问题(在 ES6 的Generator 普及之前),不过这也带来了更陡峭的学习曲线。一般情况下,需要半年到一年的习惯过程,当然前提是多看,多写。随着越来越多的经验分享,这个过程也在不断地缩短。

除此之外的领域,或者没有上述问题的,都都可以享受到 Node.js 带来的生产力提升和稳定的性能保障。

性能的争议

不同开发环境间的性能对比从来都是有争议的话题。我只能说,当开发 Web 或 网络环境下的应用时,Node.js 靠以下几个方面来避免出现不必要的性能问题:

Chrome V8,一个可靠的优秀的虚拟机(hidden classes 和 inline caching),让 Javascript 的运行速度进入了第一阵营(C++, Java, .NET)。

异步 IO 大大降低了线程数量,莫名其妙的死锁和等待的概率被降低了很多。大部分场景不用去考虑并发和同步锁,犯错误的机会少。而在 Python 中,异步 IO 并不是标准,并没有被贯穿到所有 Package 中,因此应用程序也就很难获得一致的性能保障。

非常轻巧的“内核”。Node.js 的模块分为 Core Modules 和 Userland 两部分。Core Modules 非常精简,只包括 TCP, HTTP, DNS, File System, child processes 和其他一些模块,这些网络库还只有异步版本。相对地,在 Userland 中却有着海量的 Packages。开发应用的时候,我们根据应用的需求来组合 Userland 的 Packages,使得我们的应用程序有机会在一个很低的资源消耗水平下运行(在《Announcing ql.io》中指出,一台开发服务器就可以支持 12 万活跃连接,平均每个连接消耗 2k 内存)。事实上,我开发的 WebSockte 应用在 Raspberry Pi 下都可以支持几百并发长连接(WebSocket)。和那些动辄上万个类的企业开发框架相比,这是一个巨大的优势。这种方式降低了出现问题的概率、查找问题的成本以及减少部署成本。

对 Javascript 的绝对性能的追求一直没有停顿(例如, Mozilla 的 asm.js )。而 Node.js 则在绝对性能的基础上,确保应用程序可以获得稳定和可预测的性能保障( Benchmark 和实际的应用运行往往是两回事)。

Node.js继承了JavaScript 的灵活性,优秀的JS库应当如何选择

可以在 npmjs.org 或者 google 上搜索关键词。如果类似的返回很多,则看其被其他 package 依赖的数量有多少。上 github 上查看 starred 和 forks 的数量,读 issues。

如果是“名人”(substack, visionmedia (TJ Holowaychuk), dominictarr, rvagg 等)写的 Packages 自然会被加分。

最后是把 Git Repo. Clone 或者 Fork 下来, 阅读且注释他们的源代码。这个过程也可以发现很多他们依赖的其他 Packages。这是一个蛮享受的过程,可以学到很多新知识和新的用法。

还有一些乱枪打鸟的方法:

在 Tweeter 上关注 @nodenpm,所有在 npm 上发布或者更新的 packages 都会在该 handle 上发布出来。在你的碎片时间没事可以刷刷这个,当然你需要 APN 翻墙。

关注一些推荐和评论账号:@dailyjs,@echojs 等。

Changelog 会提供不错的开源信息汇总,其中包括 Node.js、Javascript 和 npm 栏目。

Hacker News 则不会让你忽略软件行业的一些“大事”或者新概念。

一个项目开始前的研究阶段,我大约会浏览几十个 Packages,精读其中的5 ~ 10个。开发过程中则根据需要还会不断地发现和精读一些,这些都被我计入了项目的成本。

"自由选择,自己负责",在这个庞大的开发社区了不要指望有人能告诉你“标准答案”。每个人面临的问题域和知识背景都不一样,坚持多看,多试,多思考,享受获得新知识的过程比获得“标准答案”更重要。

在众多的成熟开发框架下为什么需要Node.js

在每一个特定的问题域,大家总是在尝试找到最优解。这个过程是没有终结的,就想最终也会有其他框架代替 Node.js 一样。

今天的 Web,是无数相互连接的 Web Services 组成的,这些连接的本质是异步的。Node.js 天生异步的特性和这个场景的匹配度相对其他开发框架要更高,因此实现起来也更自然。

除此之外,Node.js 的设计基本原则遵循了 《Unix 的编程艺术》,参见 Isaac Z. Schlueter (前任 Node.js 的Gatekeeper,目前负责 npm 的商业化) 的Blog: Unix Philosophy and Node.js。

npm 和 stream 就是上述哲学的产物。

npm

npm 是 Node.js 的包管理系统。包管理系统不是新东西,但是和 npm 的那些前辈和表兄弟不同的是:

npm 直接集成在 Node.js 中,无需单独安装,发布,安装 packages 非常简单。

npmjs.org 提供一个统一的入口,你可以看到每个 package 被哪些 packages 所依赖,你也可以一目了然地看到它依赖了誰,以及最近的下载次数。结合到 github 上的更新情况,基本上对一个 package 的基本情况你都能了解到。

约定俗成的发布规范:一个 git repo. 让你可以直接找到源代码;README.md 提供简要的说明让消费者能尽快用起来。

对于开发者来说,每一个 package 就是一个 "micro service",是最小重用单元。大部分的 package 只有几百行代码,甚至有些只有几行代码。这样的重用粒度是在其他社区难以想象的。

在 Node.js 的应用的开发过程中,编写 “一口尺寸”(bite-size)的 module 是推荐的编程方式。这也很方便你把这些小 module 封装为 package 分享到社区当中,而不用担心泄露“企业机密”。

npm 是每一个 Noder 的 "home",也是每一个 Node.js 应用的系统架构的一部分。


上一篇:开发者须知:哪些广告最让用户感到厌烦
下一篇:5个开源项目中常见的陷阱

PythonTab微信公众号:

Python技术交流互助群 ( 请勿加多个群 ):

群1: 87464755

群2: 333646237

群3: 318130924

群4: 385100854