为什么要使用Node.js?

bluegorilla 发布于1年前 阅读1214次
0 条评论

介绍

JavaScript的流行给它本身带来许多变化,Web开发的面貌也发生了巨大的改变。现在JavaScript不仅可以运行在浏览器上,甚至可以运行在服务器上,像Flash或者Java Applets那样被包装在沙盒环境中运行,这在几年前这是很难想象的。

在深入 Node.js 之前,你也许想知道使用 JavaScript跨技术栈开发 的优势,可以统一开发语言和数据格式(JSON),使开发者优化开发资源的使用。这些优势在Node.js和JavaScript的技术栈中更加明确,关于这些我们不讨论太多,这是你将Node.js加入到技术栈后最明显的优势。

维基百科中描述:“Node.js是Google V8引擎,libuv作为平台抽象层,JavaScript编写的核心库封装编译的。”不仅如此,值得注意的是Node.js的作者Ryan Dahl目的是构建 一个有实时推送能力的网站 。灵感来自类似Gmail的应用。在Node.js中,他提供给开发者工作在事件驱动、非阻塞I/O的模型。

有人说:Node.js在使用WebSocket的推送技术创建的实时web应用中大放异彩。为什么这它引起巨大的改变?在经过长达20多年基于无状态请求响应模型中,我们最终有了实时、全双工通信的Web应用,浏览器和服务器都可以初始化建立连接,自由的交换数据。这和传统的基于客户端初始化连接的Web响应模式有明显的对比。它们都是基于Web技术栈(Html, CSS, JS)运行在80端口上。

有人也许会说,我们已经以Flash和Java Applets的形式使用过很多年了。但实际上它们只是运行在沙盒环境里通过Web传输协议发送到客户端,它们孤立地运行在非标准端口,这可能会引入其他问题比如权限问题。

因为这些优点,现在Node.js在那依赖自己独特利益的大公司的技术栈里扮演着关键性的角色。Node.js基金会整理了所有最佳实践,关于企业为什么应该考虑使用Node.js。你可以在一篇 短文 中找到它。

这篇文章中,我不仅讨论那些已经实现的优点,还会结合一些经典的Web应用模型,告诉你为什么你要使用Node.js,以及为什么不要使用Node.js。

它是怎样工作的?

Node.js最主要的特点:使用非阻塞、事件驱动I/O模型使其轻量、高效,能够构建数据密集型、实时的跨平台应用。这说明Node.js并不是一颗主宰整个Web开发世界的银弹。相反,它是 一个解决特殊需求的平台 。明白这些是必要的,不要使用Node.js处理CPU密集型业务,如果你真的这么做了,我们先前说过关于Node.js的优点都将不复存在。Node.js真正适合的是构建快速的、可扩展的网络应用,他的吞吐率能够胜任巨量的并发连接。

和传统的Web服务技术相比,每个请求到来创建一个新的线程,系统为每个线程分配内存,最终因为内存不够而透支,Node.js工作在单线程,使用非阻塞I/O调用,能够承受上万的并发连接。我们很快得出一个结论:假设每创建一个线程系统为它分配2M内存,在一台8G内存的系统上它的最大并发数是4000(这个结论来自Michael Abernethy的文章《Just what is Node.js?》,于2011年出版在IBM developerWorks,不幸的是现在不能阅读了),加上线程 上下文切换 的花费,这是使用传统Web服务技术的场景,Node.js实现的可扩展性远远超过它。

为什么要使用Node.js?

当然所有客户端请求都使用同一个线程是有问题的,它是Node.js应用的一个潜在陷阱。首先,大量的计算会阻塞单线程直到计算完成。第二,开发者一定要注意不要让异常冒泡到应用顶部,这可能使整个Node.js程序崩溃。

避免异常冒泡到程序顶部,可以将错误当做回调函数的参数。即使有些未捕获的异常,开发工具能够监视Node.js进程,并且完成必要的崩溃实例恢复(当前用户的session是没有办法恢复的),最常使用的工具就是forever,或者外部系统工具,也可以直接重启。

NPM: Node包管理工具

当我们讨论Node.js时,需要了解一下 NPM ,它是内置用来管理Node.js包的工具,安装Node.js时就会默认安装它。NPM的思想和Ruby的Gem十分相似:一个可公开的、可重用的组件库,可通过在线仓库轻松安装,能够进行版本和依赖项管理。

下面是一些NPM包,你可以在 NPM官网 找到它们,或者使用NPM命令行工具下载到你的Node.js项目里。NPM是一个开发的生态系统,任何人可以发布自己的NPM模块,并在NPM官网上找到它。你可以在 Beginner’s Guide 上找到一份简介,还有一份开发NPM包的指南 开发NPM包的指南 .

这是我们经常用到的一些NPM包:

  • express - Express.js是一个受Sinatra启发的Node.js的Web开发框架,它是今天大部分Node.js应用程序的事实上的标准。

  • koa - 和Express是同一个作者,基于中间件机制的Web框架,比Express更加轻量。

  • socket.io - Node.js服务端实时应用的框架。

  • request - 一个HTTP客户端请求工具。

  • async - async是一个用来处JavaScript异步操作的工具库。

  • bluebird - bluebird实现了Promise/A+规范,是一款性能非常好的Promise工具库.

  • lodash and underscore and Ramda-是JavaSciprt的扩展库,提供了丰富的方法。

  • debug - 开发过程中用到的调试工具。

  • forever and nodemon- 常用的进程守护工具,上文提到过,可以在开发模式下保护你的进程。

可以用Node.js实现的应用

聊天室

聊天是典型的实时、多用户应用。在当时IRC通过许多专有和开放的协议运行在不标准的端口上,现在在Node.js环境下,我们可以在标准的80端口上,实现这些聊天应用。

可以说聊天应用是体验Node.js优点最好的例子,聊天应用轻量化、高流量,数据密集型(计算和处理时间短,最简单做一次转发)、跨终端、也是学习Node.js绝佳的例子,它包含了大多数在一个典型的Node.js应用中用到的模式。

分析一下聊天室是如何工作的。

最简单的例子,在我们的站点上只有一个聊天房间,所用的用户采用一对多的形式交换消息。假设我们的房间里有三个已经建立连接的用户。

在服务端,我们有一个简单的Express.js的应用,它实现两个功能:1.当我们请求根目录时,它返回一个包含消息面板,用来发送消息的按钮,还有输入框的网页。2.一个websocket服务,监听新消息并发送给客户端。

在客户端,我们有一个监听两个事件的页面,其中一个监听发送按钮点击事件,获取输入框中的消息,并通过websocket发送到服务端,另一个事件监听websocket客户端新消息(这个消息来源于其他用户,服务端转发给所有在这个聊天房间的用户,并且客户端显示消息)。

当一个用户发送消息,会经过如下几步:

  1. 浏览器监听发送按钮点击,JavaScript处理事件,从输入框中获取消息内容,websocket发送消息。

  2. 服务端webSocket连接收到消息,通过使用broadcast方法,进一步将它转发给其他建立连接的用户。

  3. 所有用户通过客户端websocket收到了来自服务端的推送消息,客户端将得到的消息,追加到页面消息面板的适当位置。

为什么要使用Node.js?

这是最简单的例子了,如果你想让它更加健壮,你可以使用如Redis这样的高速缓存,或者更高级一点,用消息队列处理客户端的消息分发,并且建立更强大的连接机制,用来减少建立临时连接的损失,还可以为已经注册的用户保存离线消息。不管你是否能实现这些功能,Node.js的最基本的功能仍是处理事件和并发连接,并且保证用户体验的流畅性。

非关系型数据库数据接口

Node.js不仅在实时应用上做的很出色,它和非常适合从非关系型数据库读取数据。Node.js使用JSON存储数据,可以无阻抗失配,不需要数据转换。

举个例子,如果你使用用Rails开发,你会将JSON数据转换为二进制数据,然后通过Http协议发送到浏览器,数据需要转换为JSON格式才能被Backbone.js,Angular.js等框架或者普通Ajax调用。如果你使用Node.js开发,你可以通过REST API返回JSON对象给浏览器使用。此外,你也不需要担心在读写数据库(MongoDB)时会发生数据转换错误。总之,你可以不必在客户端、服务器、数据库使用统一序列化格式。

队列

如果你的应用有高并发的数据,数据库会成为应用的瓶颈。上文提到,Node.js可以轻松地处理高并发连接,但是数据库访问却是阻塞的操作,在这种情况下,我们就有麻烦了。解决方案就是,我们先接受客户端的请求,并返回结果,然后才真正的写到数据库中。

使用这种方法,系统能在高负载的情况下保证响应能力,尤其是在客户端不需要确认是否存数据存储成功的情况下。最典型的例子就是:日志或者记录用户行为的数据,批次处理并且不会立刻使用的情况;操作不需要立刻做出反应(就像Facebook更新点赞数据),在使用NoSQL的情况下是可行的。

数据通过某种缓存或者消息队列(如:RabbitMQ,ZeroMQ)进行排队,等待被数据库写线程批量写入,或者计算密集型的后端服务进行处理。相似的行为可以通过其他语言或者框架来实现,但是在相同的硬件下,Node.js能保持更高的吞吐量。

为什么要使用Node.js?

数据流

在传统的Web平台,HTTP请求和响应被当做孤立的事件来对待;实际上他们都是数据流。这个事实被Node.js利用构建一些很酷的特性,例如:我们可以在文件上传过程中就进行处理,由于数据是以流的形式传输过来,我们可以在线处理它。可以用来做实时语音或视频的编码,在不同的数据源之间做代理。

代理

Node.js和容易搭建一个服务端代理,它可以以非阻塞的方式处理大量并发连接。尤其是用在为不同响应时间的服务做代理,或者从多个源点收集数据。

举个例子:服务端应用需要和第三方资源沟通,从多个源点拉取数据,或者将图像视频等资源存储到第三方服务。

尽管专用代理服务确实存在,你可以在代理基础设施不全或者需要本地开发的解决方案时用Node.js来实现。在开发时你可以使用Node.js服务搭建静态资源客户端应用,代理API请求。在生产环境下你可以使用专用代理服务,如:nginx、HAProxy等。

中间层

让我们回到应用水平。中间人交易软件在桌面软件占主导地位,但很容易用实时网络解决方案代替,它用来跟踪股票价格,进行计算/技术分析,并创建图表。如果是基于Web的实时应用的解决方案,经纪人轻松地切换工作站或工作场所。

应用监控

另一种常见的场景,在Node.js中使用WebSocket技术跟踪网站访问者并实时可视化他们的交互。你可以从你的用户那里收集实时的统计数据,甚至可以通过在你的漏斗中到达一个特定的点,打开一个通信通道来与访问者进行有针对性的交互,从而将其移动到下一个层次。(如果你感兴趣,可以去了解 CANDDi ,它已经把这个想法产品化了)。

系统监控

现在我们聊一条基础设施方面的问题。设想一下,有一个Sass平台想要提供给用户一个服务监控页面,例如 GitHub’s status page 。使用Node.js的事件循环机制,我们可以构建一个强大的信息板,来监控服务器的状态,以异步的方式将数据通过WebSocket发送到客户端。

不管是内部还是公众服务,都可以通过这种技术实时报告状态。我们进一步推动这个想法,然后想象一个工作在电信运营商的 Network Operations Center (NOC) 监控应用,云/网络/主机提供商,或者是一些金融机构,都运行在Node.js和WebSockets技术栈上,而不是java或java小应用程序。

注意:不要试图使用Node.js构建硬实时系统,即那些要求一致响应时间的系统。 Erlang构建这类应用 或许是更好的选择

Node.js适合用在哪?

web应用程序

使用Express.js框架可以在服务器上构建一个传统的Web应用,有一种说法,Node.js的请求响应模型用来渲染HTML页面不是最好的用处。这个观点是有争议的,他们的考虑如下:

赞成的观点:

  • 如果你的应用没有CPU密集的处理,你可以使用Node.js构建自上而下的应用,或者做最底层对象关系数据库(MongoDB)的读写,这大大简化了开发。

  • 爬虫抓取到一个完成的HTML响应,要比得到一个单页面或者使用WebSocket的应用,对SEO更加友好。 反对的观点:

  • 任何CPU密集型的业务将会阻塞Node.js的响应,如果没有这种业务单线程表现很好,相反的,你可以增加CPU的运算量试试。

  • 使用Node.js时,任何关系型数据库都是相当痛苦的(详情见下文),如果你确定要用关系型数据库,帮自己一个忙,你可以试试Rails,Django,或者ASP.Net。

有一个替代CPU密集型业务的解决方案,创建一个告诉可伸缩的消息队列后台程序,Node.js像前台接待员一样异步地接受客户端请求。

Node.js不适合用在哪?

使用关系型数据库的Web应用程序

Node.js的Express.js和Ruby on Rails进行比较,后端访问关系数据库干净的决策比较受到支持。

Node.js关系数据库工具发展仍在早期阶段;它们工作的相当不成熟也不友好。另一方面,Rails自动提供数据访问设置权开箱与DB模式迁移的支持工具和其他Gems。Rails及其对等框架具有成熟的、已证实的活动记录或数据映射器数据访问层实现,如果你试图以纯JavaScript复制它们,你会非常怀念这段经历。

你若你还想继续走Node.js这条路,准备好掉头发吧。记得关注一下 SequelizeNode ORM2 两者都还不成熟,但最终可能会迎头赶上。

将Node.js单独用作前端是可能的,而且并不少见,同时保持Rails后端和对关系数据库的简单访问。

沉重的服务端计算

当涉及到大量的计算,Node.js是不是最好的平台。你肯定不想使用 Node.js建一个斐波纳契计算服务器 ,总之,任何CPU密集型操作都会使Node.js事件驱动,非阻塞I/O的的模型变得毫无作用,因为请求会被阻塞,因为线程被你的数字梳理给占据了。

如上所述,Node.js使用单线程并且只使用单核CPU,如果你打算在多核CPU上部署服务,Node.js核心团队开发了 集群 模块。你也可以建立多个Node.js引用实例,让后通过Nginx代理到它们。

在使用集群是,你还是应该将计算量重的操作放到像RabbitMQ这样的消息队列里,在合适的时候拿出来处理。

尽管最初的后台处理可能在同一台服务器上运行,但这种方法具有非常高的可伸缩性。这些后台处理服务可以很容易地分发到分离的worker服务器,而无需配置前向Web服务器的负载。

当然,你可以在其他平台上使用一样的做法,但Node.js有高的请求/秒的吞吐量,我们已经谈过,因为每个请求是一个小的任务处理的非常快速和有效的。

总结

我们从理论到实践讨论Node.js,从它的目标和抱负开始,到它的甜头和陷阱。当开发者遇到Node.js的问题时,认为 阻塞是万恶之源 ,99%的原因是滥用Node.js造成的。

记住,Node.js不是为了解决计算扩展问题而产生的,而是为了解决I/O扩展问题,在这方面它 做的很出色

为什么使用Node.js?如果您使用的情况不包含CPU密集型操作或访问任何阻塞的资源,你可以利用Node.js的好处,构建快速和可扩展的网络应用。欢迎来到实时Web应用。

查看原文: 为什么要使用Node.js?

  • crazyostrich
  • tinyduck
  • purplefrog
  • silverlion
  • tinymeercat
  • ticklishladybug
  • whitesnake
需要 登录 后回复方可回复, 如果你还没有账号你可以 注册 一个帐号。