Node.js具体解析

介绍javascript

JavaScript 高涨的人气带来了很是多变化。以致于如今使用其进行网络开发的形式也变得大相径庭了。就如同在浏览器中同样,如今咱们也可以在server上执行 JavaScript ,从前端跨越到后端,这样巨大的反差让人不可思议。因为只在几年前 Javascript 还如同 Flash 或者 Java applet 那样嵌入网页在沙箱环境中执行。html

在深刻Node.js以前。你可能需要阅读和了解使用跨栈式JavaScript(JavaScript across the stack)带来的优势,它统一了编程语言和数据格式(JSON),让你能最佳地重用开发者资源。由于这不少其它的是关于 JavaScript 的特色。这里就只是多讨论它。前端

但它确实是一个让人在开发环节中使用 Node 的关键的长处。java

正如维基百科 所说:“Node.js 是谷歌 V8 引擎、libuv平台抽象层 以及主体使用 Javscript 编写的核心库三者集合的一个包装外壳。” 除此以外,值得注意的是,Node.js 的做者瑞恩·达尔 (Ryan Dahl) 的目标是建立具备实时推送能力的站点。在 Node.js 中,他给了开发人员一个使用事件驱动来实现异步开发的优秀解决方式。node

(注:V8是谷歌开发的,眼下公认最快的 Javascript 解析引擎,libuv 是一个开源的、为 Node 定制而生的跨平台的异步 IO 库。)nginx

简而言之:Node.js 在实时的 Web应用上採用了基于 WebSocket 的推送技术。git

这意味着什么样的革命性?Well,在通过了20多年的基于无状态的请求-返机制的无状态交互以后,咱们最终有了实时的。双向链接的web应用。client和server端均可以发起通讯。能够自由地交换数据。与此造成鲜明对照的是传统的 web响应模式,client老是主动发起通讯而服务端被动返回。github

此外,这些都是基于执行在标准80port上的开放Web组件(HTML、CSS和JS)。web

可能有人会说,咱们已经使用 Flash 和 Java Applet 的形式很是多年了——但实际上。这些方式仅仅是使用网络将数据传递到client上的沙箱环境。他们都是隔离执行的。而且经常操做到需要额外的权限之类的非标准port。redis

凭借其独特的优点,Node.js的现在已经在不少著名公司的产品中起到了关键做用。

在这篇文章中。咱们不只将讨论这些优点是怎样实现的,而且也会讨论为何你使用 Node.js 来替代一些经典的Web应用程序模型。

Node.js 是怎样工做的?

Node.js 的主要思路是:使用非堵塞的,事件驱动的 I/O 操做来保持在处理跨平台 (across distributed devices) 数据密集型实时应用时的轻巧高效。这听起来有点绕口。

它的真正含义是,Node.js 不是一个即将主导Web开发的世界的银弹级的平台。

相反,它是一个知足特别需求的平台。你确定不会但愿使用 Node.js 去作 CPU密集型操做。其实,使用它进行繁重的计算等于摒弃 Node 差点儿所有的长处。Node 真正的亮点在于建设高性能,高扩展性的互联网应用——因为它能够处理庞大的并且高吞吐量的并发链接。

它的工做原理是至关有趣的。传统的网络服务技术,是每个新增一个链接(请求)便生成一个新的线程,这个新的线程会占用系统内存,终于会占掉所有的可用内存。

而 Node.js 只只执行在一个单线程中,使用非堵塞的异步 I/O 调用,所有链接都由该线程处理,在 libuv 的加分下,可以赞成其支持数万并发链接(所有挂在该线程的事件循环中)。

toptal-blog-1_B

作一个简单的计算: 若是是普通的Web程序,新接入一个链接会占用 2M 的内存,在有 8GB RAM的系统上执行时, 算上线程之间上下文切换的成本,并发链接的最大理论值则为 4000 个。这是在传统 Web服务端技术下的处理状况。

而 Node.js 则达到了约 1M 一个并发链接的拓展级别 (相关证实).

固然。在所有client的请求共享单一线程时也会有问题, 这也是一个编写 Node.js 应用的潜在缺陷. 首先, 大量的计算可能会使得 Node 的单线程临时失去反应, 并致使所有的其它client的请求一直堵塞, 直到计算结束才恢复正常。 其次,开发者需要很当心,不要让一个 Exception 堵塞核心的事件循环,因为这将致使 Node.js 实例的终止(实际上就是程序崩溃)。( 笔者注:如 PHP 中某个页面挂掉是不会影响站点执行的,但是 Nodejs 是一个线程一个线程来处理所有的连接,因此不管是计算卡了或者是被异常堵塞了均可能会影响到其它所有的连接。解决方式在稍后讨论。)

用来避免异常抛出时中断进程的方法是将异常使用回调传递出去(而不是抛出他们。就像在其它环境中同样)。即便一些未处理的异常堵塞了程序,依然有多种应对的解决方式,而且也有很是多可用于监视 Node 进程来运行必要的崩溃后恢复工做的策略和工具(尽管你将没法恢复用户的 Session )。最多见的是使用 Forever 模块。或者採用其它的外部系统工具如 upstart and monit

NPM: The Node Package Manager

当咱们讨论 Node.js 的时候,一个绝对不该该忽略地方就是默认内置的模块管理工具 —— NPM。 其灵感来源与 Ruby Gems(具备版本号和依赖管理功能。可以经过在线资料库便捷安装可重用的组件的管理工具)。

一个完整的公用模块列表可以在 NPM 的站点上找到(https:://npmjs.org/),或者经过使用与 Node.js 一同安装的 NPM CLI 工具放问到。该模块的生态系统向所有人开放,不论什么人都可以公布本身的模块,所有的模块都可以在 NPM 资料库中找到。你可以在 http://howtonode.org/introduction-to-npm 页面找到 NPM 的一个简要介绍(有点旧,但依然能看)。

眼下很流行的一些 NPM 模块有:

  • express – Express.js,是一个简洁而灵活的 node.js Web应用框架, 并且已是现在大多数 Node.js 应用的标准框架。你已经可以在很是多 Node.js 的书籍中看到它了。
  • connect – Connect 是一个 Node.js 的 HTTP 服务拓展框架,提供一个高性能的“插件”集合,以中间件闻名,是 Express 的基础部分之中的一个。

  • socket.io 和 sockjs – 眼下服务端最流行的两个 websocket 组件。
  • Jade – 流行的模板引擎之中的一个,并且是 Express.js 的默认模板引擎。其灵感来源于 HAML。

  • mongo 和 mongojs – 封装了 MongoDB 的的各类 API,只是笔者寻常工做用的是 mongoose 也很是推荐。
  • redis – Redis 的client函数库.
  • coffee-script – CoffeeScript 编译器,赞成开发人员使用 Coffee 来编写他们的 Node.js 程序。
  • underscore (lodashlazy) – 最流行的 JavaScript 工具库 , 用于 Node.js 的封装包,以及两个採取略有不一样的实现方法来得到更好性能的同行。
  • forever – 多是用来确保 node 脚本持续执行的最流行的工具。

还有很是多好的模块。这里就不一一列举了(但愿没有冒犯到没列举的)。

Node.js 应该用在什么地方

聊天

聊天是最典型的多用户实时交互的应用。从 IRC 開始,有不少开源或者不开源的协议都执行在非标准port上,而现在,使用 Node.js 则可以解决这些问题——在标准的80port执行 WebSockets。

聊天应用程序是最能体现 Node.js 长处的样例:轻量级、高流量并且能良好的应对跨平台设备上执行密集型数据(尽管计算能力低)。

同一时候。聊天也是一个很是值得学习的用例。因为它很是easy,并且涵盖了眼下为止一个典型的 Node.js 会用到的大部分解决方式。

让咱们试着来描绘它怎样工做。

在最简单的状况下。咱们布置了一个聊天室在咱们的站点上,用户可以在上面发消息,固然是一对多的形式。

好比,若是总共同拥有三我的链接到咱们的站点上。

在服务端这边。 咱们有一个使用 Express.js 搭建的简单网站,该网站实现了两件事 1) 处理路径为 ‘/’ 的GET请求时,下发包含一个留言板以及一个发送信息的 ‘发送’ button的页面 2) 一个监听client发送新消息的 websockets 服务。

在client这边,咱们有一个 HTML 页面,上面有个两个 js 方法,一个是用于触发事件的 “发送” button,这会把把输入的消息经过 webscoket 发送,还有一个方法是用 webscoket 在client上监听服务端来的推送(好比。其它用户发送的消息)。

当有一个client发送消息的时候,发生的事情是:

  1. 浏览器上,点击发送button触发了 js 函数。将输入框中的文字经过 websocket 消息发送到server的 websocket client(页面初始化载入的时候链接的)。
  2. 服务端的 websocket 组件收到 消息,而后经过广播方法转发到其它所有链接的client。

  3. 经过页面上执行的 websocket client组件,所有的client都能收到这条推送的新消息。接着 js 处理函数可以把这个消息加入到文字框内。

toptal-blog-2_B

这是一个最简单的样例。假设要更好的解决方式。你可以使用 Redis 数据库作一个简单的缓存。在一个更高级的解决方式中,你可能需要一个消息路由来专门处理消息队列。并且需要一个更强健的发送机制。比方发送的时候覆盖上临时离线的用户或者为离线的注冊用户存储还没有接收的消息等等。但是不论你作了怎么样的改进,Node.js 都将遵循一个基本原则:响应事件,处理多个并发链接,并保持流动性的用户体验。

对象数据库接口(API ON TOP OF AN OBJECT DB)

虽然,Node.js 确实很擅长实时交互的应用,同一时候它也十分适合经过对象数据库(object DB)来查询数据(如 MongoDB)。

以 JSON 格式存储的数据赞成 Node.js 直接处理。不需要纠结数据转换和匹配的问题。

举个样例。假设你正在使用 Rails。你会将 JSON 数据转成 二进制的 model,当数据再被 Backbone.js, Angular.js 或者 jQuery AJAX 之类的调用又要转回 JSON。假设是 Nodejs 的话,你可以经过一个 REST API 简单的导出 JSON 对象以供client使用。

另外,从数据库读写时候假设使用的是 MongoDB 的话。你也不用操心的 JSON 与不论什么数据之间的格式问题。

总之。你可以避免多元的数据转换问题,不管是在client、服务端仍是数据库。

队列输入

假设你正在接收一个高量并发的数据,你的数据库可能会成为你处理的瓶颈。正如上面的描写叙述。Node.js 可以轻松的处理并发链接。

但是,由于数据库操做是一个堵塞的操做(在这样的状况下),这就是麻烦的地方。Node.js的解决方式是,在数据真正的写入以前就认可client的数据是真实的。

用这样的方法,在高负载的时候系统继续维持它的响应。这在当client不需要严格确认一个数据是否成功的被写入时特别实用。典型的样例包含:日志记录或者用户跟踪数据(user-tracking data)的记录,这会被分批处理并且在稍后才使用;同一时候也包含终于一致性(so, 常用于 NoSQL)可以接受,不需要立刻反应的操做(好比 Facebook 上更新点赞的数目)。

数据经过某些缓存或者消息队列的基础组件(好比 RabbitMQ, ZeroMQ)进入队列。并且经过一个独立的数据库批量写入进程来一一消化。或者经过一个更高性能的计算密集型后端服务来进行处理。其它的语言/框架也可以实现类似的操做。但在一样的配置下是达不到 nodejs 的高吞吐量与高并发。

toptal-blog-3_B

简单的说:使用 Node,你可以把数据库操做扔到一边并在稍后处理它们,若是他们成功了同样继续运行下去。

(笔者注:在开发中一般的状况通常是,种耗时的操做经过回调函数来异步处理,主线程继续往下运行)

数据流

在较为传统的网络平台上。HTTP 的请求和响应更像是孤立的事件;然而其实,他们都是数据流。这一观察结果在 Nodejs 上可以用来创建一些很是酷的功能。因为数据通以流的形式接收,而咱们可以在站点上在线处理正在上传中的文件。这种话,就可以实现实时的音频和视频编码,以及在不一样数据源之间进行代码(代理见下一段)。

(笔者注:Node 有取代如 apache 这种 webserver 处理数据。因此开发人员可以直接收到client一份一份上传的数据,并实时处理。上面这段话听起来有点抽象。只是各位可以简单的想象一下不需要开 YY 或者 QQ。打开网页就能进行语音视频的功能。)

代理

Node.js 可以经过异步的方式处理大量的并发链接,因此很是easy做为服务端的代理来使用。这在与不一样响应时间的不一样服务之间进行代理。或者是收集来自多个来源的数据时尤事实上用。

举个样例:考虑一个server端的应用程序和第三方资源进行通讯以更新自不一样来源的数据,或者将服务端上的一些图像和视频资源存储到第三方云服务。

尽管专用代理server确实存在,但是假设你尚未专用的代理server,或者你需要一个本地开发的解决方式,那么使用 Node 来作代理多是更好的选择。关于这个解决方式。个人意思是指当你在开发的时候,你可以使用Node.js的开发环境搭建一个服务来处理对资源和代理的请求。而在生产环境下,你可以使用专用的代理服务(比方nginx。HAProxy等)来处理这些交互。

股票操盘手的仪表盘

让咱们继续讨论应用程序这块。

实时网络的解决方式可以很是轻松的实现证券交易软件——用于跟踪股票的价格,运行计算、作技术分析,同一时候生成报表。

使用一个实时的的基于网页的解决方式。将会赞成操盘手轻松的切换工做软件以及工做地点。相信不久,咱们也许会在 佛罗里达州、伊维萨岛又或者是巴厘岛的海滩上看到他们。

应用监听仪盘表

还有一种常见的用例中,使用 Node+Web+Socket 很适合:跟踪站点訪问者并且可视化实时它们之间的实时交互。

(假设你有兴趣,可以去看看 Hummingbird

你可能需要採集用户的实时状态, 或者甚至当他们到达渠道中某个特定的点时, 打开一个交流频道, 经过有针对性的互动介绍移动到下一个阶段. (假设你感兴趣的话。推荐你看看 CANDDi

想象一下。假设你知道你的訪客的实时操做。并能够形象化地看到他们的交互,这将对你的业务带来多大的提高。随着实时的、双向 socket 通讯的 Node.js ,现在你能够作到了。

系统监控仪表

现在,让咱们看看事情的基础设施方面。想象一下,比方,但愿为其用户提供服务监控页面(好比,GitHub上的状态页)的 SaaS 运营商 。经过 Node.js 的事件循环,咱们可以建立一个基于 Web 的功能强大的仪表板,以异步方式检查服务状态并且使用的 WebSockets 将数据推送到client。

内部(公司内部)和公共服务的状态都可以使用该项技术实现实时的上报。让咱们把这一想法延伸的远一点,试着想象一个电信运营商中网络运营中心(NOC)的监控应用。云/网络/server运营商,或者一些金融机构。全都执行在这个由 Node.js 和 WebSocket 组成的应用上,而不是 Java 和/或 Java Applet。

注意:不要尝试使用 Node 打造硬实时系统(即,响应时间要求一致的系统)。 Erlang是多是该类应用程序的更好的选择

什么地方可以使用 Node.js

服务端 WEB 应用

经过 Node.js 使用 Express.js 也可以用来建立服务端上的典型的网页应用。然而,尽管有可能,使用 Node.js 来进行请求+响应的形式来呈现 HTML 并不是最典型的用例。

有人同意也有人反对这一作法。这里有一些见解以供參考:

长处:

  • 假设你不需要进行 CPU密集型计算,你可以从头至尾甚至是数据库(比方 MongoDB)都使用 Javascript 来开发。这显著地减轻了开发工序(包含成本)。
  • 对于一个使用 Node.js 做为服务端的单页应用或者 websocket 应用,爬虫可以收到一个全然 HTML 呈现的响应,这是更为SEO友好的。

缺点:

  • 不论什么CPU密集型的计算都将阻碍 Node.js 的反应,因此使用多线程的平台是一个更好的方法。或者,您也可以尝试向外扩展的计算[*]。
  • Node.js 使用关系型数据库依然十分痛苦(具体见下方)。

    拜托了。假设你想运行关系型数据操做。请考虑别的环境:Rails, Django 甚至 ASP.NET MVC 。。。。

【*】还有一种解决方式是,为这些CPU密集型的计算创建一个高度可扩展的MQ支持的环境与后端处理。以保持 Node 做为一个前台专员来异步处理client请求。

Node.js 不该该在什么地方使用

使用关系型数据库的服务端 WEB 应用

对照 Node.js 上的 Express.js 和 Ruby on Rails。当你使用关系型数据库的时候请绝不犹豫的选择后者。

Node.js 的关系数据库工具仍处于早期阶段,眼下尚未成熟到让人能够愉快地使用它。

而与此同一时候。Rails天生自带了数据訪问组件。连同DB schema迁移的支持工具和一些Gems(一语双关,一指这些如同珍宝的工具,二指ruby的gems程序包)。

Rails和它的搭档框架们拥有很成熟且被证实了的活动记录(Active Record)或数据映射(Data Mapper)的数据訪问层的实现,而这些是当你在使用纯JavaScript来复制这些应用的时候会很想要使用的东西。

只是,假设你真的倾向于全部使用 JS(并且作好可能抓狂的准备),那么请继续关注 Sequelize 和 Node ORM2 。尽管这二者仍然不成熟的。但他们终于会迎头遇上。

[*] 使用 Node 光是做为前端而 Rails 作后端来链接关系型数据库,这是全然有可能也并很多见的。(笔者注:国外有种说法。PHP这一类程序猿也可以算做是前端)

繁重的服务端的计算和处理

当涉及到大量的计算,Node.js 就不是最佳的解决方式。你确定不但愿使用 Node.js 创建一个斐波那契数的计算服务

普通状况下,不论什么 CPU密集型操做 会削弱掉 Node经过事件驱动, 异步 I/O 模型等等带来的在吞吐量上的优点,因为当线程被非异步的高计算量占用时不论什么传入的请求将被堵塞。

正如前面所说,Node.js 是单线程的。仅仅使用一个单一的CPU核心。

至于,涉及到server上多核并发处理。Node 的核心团队已经使用 cluster 模块的形式在这一方面作了一些工做 (參考:http://nodejs.org/api/cluster.html)。

固然。您也可以很是easy的经过 nginx 的反向代理执行多个 Node.js 的server实例来避免单一线程堵塞的问题。

关于集群(clustering) ,你应该将所有繁重的计算转移到更合适的语言写的后台进程来处理,同一时候让他们经过像 RabbitMQ 那样经过消息队列server来进行通讯。

即便你的后台处理可能最初执行在同一台server上时看不出什么长处,但是这种作法具备很高的可扩展性的潜力。这些后台处理服务可以easy地切割出去。做为单独的 worker server,而不需要配置入口 webserver的负载。

固然。你也可以在其它语言平台上用相同的方法,但使用 Node.js 你可以获得很是高的吞吐量,每个请求都做为一个小任务很是迅速和高效地处理。这一点咱们已经讨论过了。

结论

咱们已经从理论到实践讨论过 Node.js 了,从它的目标和野心,到其长处和缺点。

在 Node.js 的开发中99%的问题是由误用堵塞操做而形成的。

请记住:Node.js 历来不是用于解决大规模计算问题而建立的。

它的出现是为了解决大规模I/O 的问题,并且在这一点上作的很好

综上,假设你项目需求中不包括CPU密集型操做,也不需要訪问不论什么堵塞的资源。那么你就可以利用的 Node.js 的长处,尽情的享受高速、可扩展的网络应用。

相关文章
相关标签/搜索