为何要用Node.js

翻译:疯狂的技术宅

原文:https://medium.com/the-node-j...javascript

未经许可,禁止转载!html


本文首发微信公众号:前端先锋
欢迎关注,天天都给你推送新鲜的前端技术文章前端


介绍

JavaScript 的日益发展带来了不少变化,当今的 Web 开发面貌已经变得大相径庭。在几年前是很难想象在服务器上运行 JavaScript 的。java

在深刻研究Node.js以前,你可能想了解使用跨栈的 JavaScript 有什么好处,它统一了语言和数据格式(JSON),容许你以最佳的方式重用开发人员资源。将 Node.js 合并到技术栈中是一个关键优点。node

Node.js 是一个基于 Chrome 的名为 V8 的 JavaScript 引擎构建的 JavaScript 运行环境。值得注意的是,Node.js 的建立者 Ryan Dahl 的“受到 Gmail 等应用的启发”,目标是为了开发一个具备实时推送功能的网站。在 Node.js 中,他提供了一个用于处理非阻塞事件驱动的 I/O 工具。nginx

用一句话来归纳:Node.js 在基于websockets 推送技术的实时 Web 应用中大放异彩。在过去的 20 多年来咱们一直在使用基于无状态请求 - 响应模式的无状态 Web 应用,如今终于拥有了可以实时双向链接的 Web 应用,其中客户端和服务器均可以启动通讯,并容许它们自由地交换数据。git

这与典型的老是由客户端发起通讯的 Web 响应模式形了成鲜明的对比。此外它也一样基于在标准端口 80 上运行的开放 Web 技术栈(HTML,CSS和JS)。程序员

有人可能会争辩说,咱们多年来一直以 Flash 和 Java Applet 的形式作到这一点 —— 但实际上,这些只是使用 Web 做为传输协议将数据传给客户端的沙盒环境。此外,它们是隔离运行的,一般在非标准端口上运行,这可能须要额外的权限。github

凭借其优点,Node.js 在依赖其独特优点的众多知名公司的技术堆栈中发挥着关键做用。 Node.js 基金会几乎已经整合了全部最好的想法,能够在 Node.js 基金会的案例研究页面上找到关于为何企业应该考虑 Node.js 的简短PPT。web

在本文中,我将不只要讨论如何使用这些优点,并且还要讨论 为何 你可能想要使用 Node.js ,并用一些经典的 Web 应用程序模型做为示例。

它是如何工做的?

Node.js 的主要思想是:在面向跨分布式设备运行的数据密集型的实时程序时,使用非阻塞、事件驱动的 I/O 来保证轻量和高效。

这读起来很拗口。

这意味着 Node.js 不是 一个即将成为主宰 Web 开发界的可以解决一切的新平台。 相反,它是一个知足特定需求的平台。理解这一点绝对是有必要的。你毫不但愿将 Node.js 用于 CPU 密集型的操做;实际上,将它用于进行大量繁重运算的场合将会消除它几乎全部的优势。 Node.js 真正发挥做用的地方在于构建快速、可扩展的网络应用,由于它可以以高吞吐量处理大量并发链接,这至关于具备高可扩展性。

其底层的工做原理很是有趣。传统的 Web 服务技术每一个链接(请求)都会产生一个新线程,占用系统内存并最终受限于可用的最大内存,而 Node.js 在单线程上运行,使用非阻塞 I/O 调用,容许它支持数以万计的并发链接(在 event loop 中维持)。

clipboard.png

快速计算:假设每一个线程须要 2 MB 内存,那么在有 8 GB 内存的系统上运行的话,理论上最多有 4000 个并发链接(计算来自 Michael Abernethy 的文章 “Just what is Node.js?“,2011年在 IBM developerWorks 上发布;不幸的是,这篇文章的连接如今已经失效了),这尚未算上线程之间的上下文切换的成本。这就是你一般在传统的 Web 服务器技术中处理的场景。经过避免全部这些问题,Node.js 实现了超过 1M 链接并发数的级别,以及 600k 的 websockets 并发链接数

固然,编写 Node.js 应用的潜在缺陷是存在客户端请求之间共享单个线程的问题。首先,繁重的计算可能会阻塞 Node 的单个线程并致使 全部 客户端出现问题(稍后会详细说明),由于传入的请求将被阻塞,直到计算完成为止。其次开发人员须要 很是当心,不要让异常冒泡到到核心(最顶层)Node.js 事件循环,这将致使 Node.js 实例终止(程序崩溃)。

为了不异常冒泡到顶层,经常使用技术是将错误做为回调参数传递回调用者(而不是像在其余环境中那样抛出它们)。即便一些未被处理的异常冒泡到顶层,也有一些工具来监视 Node.js 进程并执行必要的恢复崩溃 (虽然可能没法恢复到用户会话的当前状态),最多见的是 Forever 模块

npm:node 包管理器

在讨论 Node.js 时,一件绝对不该该被忽略的事是支持使用内置的 npm 工具进行包管理,默认状况下每一个 Node.js 环境都会安装。 npm 模块的概念很是相似于 Ruby Gems:一组可经过在线存储库轻松安装,具备版本和依赖关系管理的可重用组件,。

能够在 npm 网站上找到已打包模块的完整列表,也可使用自动与 Node.js 一块儿安装的 npm CLI 工具进行访问。模块生态系统对全部人开放,任何人均可以发布本身的模块,发布的模块将出如今 npm 存储库中。有关 npm 的简介,请参阅初学者指南,以及 npm 发布教程中关于发布模块的部分。

一些颇有用的 npm 模块是:

  • express —— Express.js,一个受 Sinatra 启发的 Node.js Web 开发框架,当今大多数 Node.js 应用程序的事实标准。
  • hapi —— 一个模块化的且很是易于使用的以配置为中心的框架,用于构建 Web 和服务应用
  • connect —— Connect 是 Node.js 的可扩展 HTTP 服务器框架,提供了一系列称为中间件的高性能“插件”做为Express的基础。
  • socket.iosockjs —— 今天最多见的两个 websockets 服务器端组件。
  • pug(之前叫 Jade)—— 受 HAML 启发的流行模板引擎之一,Express.js 中的默认选项。
  • mongodbmongojs —— MongoDB 包装器,为 Node.js 中的 MongoDB 对象数据库提供 API。
  • redis —— Redis 客户端。
  • forever —— 多是确保给定 node 脚本连续运行的最经常使用实用程序。在遇到意外故障时,将 Node.js 的进程保持在生产状态。
  • bluebird —— 功能齐全的 Promises/A+ 实现,性能很是出色
  • moment —— 用于解析、验证、操做和格式化日期的轻量级 JavaScript 日期库。

列表还在不断增加。那里有不少有用的包,可供全部人使用。

哪些场合应该使用 Node.js

在线聊天

在线聊天是最典型的实时多用户应用,也是 Node.js 的最佳案例:它是一个轻量级、高流量、数据密集型(可是低处理和计算)的应用程序,可分布式跨设备运行。它也是一个很好的学习案例,由于它很简单,但涵盖了你在典型的 Node.js 程序中所使用的大部分范例。

让咱们试着描绘它是如何工做的。

假设一个最简单的场景,在咱们的网站上有一个聊天室,人们能够经过一对多(其实是对全部人)的方式交换消息。

在服务器端,咱们有一个简单的 Express.js 程序,它实现了两件事:1) 一个GET 请求的处理程序,它提供了包含留言板和用于初始化新消息输入的“发送”按钮的功能,以及2) 用于侦听 websocket 客户端发出的新消息的w ebsockets 服务器。

在客户端,咱们有一个 HTML 页面,其中设置了几个处理程序,一个用于“发送”按钮的单击事件,它接收输入消息并将其发送到 websocket,另外一个用于侦听新的传入消息并显示在 websockets 客户端上(即服务器但愿客户端显示的其余用户发送的消息)。

当其中一个客户发布消息时,会发生如下状况:

  • 浏览器捕获单击“发送”按钮事件处理 JavaScript 程序,从输入字段(即消息文本)中获取值,并使用链接到咱们服务器的 websocket 客户端发出 websocket 消息(在网页初始化时初始化) 。
  • websocket 链接的服务器端组件接收消息,并使用广播方式将其转发给全部其余的客户端。
  • 全部客户端都经过在网页中运行的 websockets 客户端组件接收新消息。而后,他们经过将新消息添加页面上并更新。

clipboard.png

这是最简单的例子。对于更强大的解决方案,你可使用基于 Redis 的简单缓存。或者在更高级的解决方案中,能够用消息队列做为消息路由,还能够实现更强大的传递机制,例如能够在链接丢失或在客户端脱机时存储消息。但不管你作出哪些改进,Node.js 仍将按照相同的基本原则运行:对事件作出反应,处理许多并发链接,并保持用户体验的流畅性。

对象数据库顶层的 API

虽然 Node.js 的确很适合开发实时应用,但它也很适合从对象数据库(例如MongoDB)公开数据。 JSON 存储的数据容许 Node.js 在对象与存储数据一致和没有数据转换的状况下良好的运行。

例如,若是你正在使用 Rails,那么你须要从 JSON 转换为二进制模型,而后经过 HTTP 再将它们转为 JSON 在 React.js 或 Angular.js 中使用 ,甚至能够用简单的 jQuery AJAX 进行调用。使用 Node.js,你能够经过 REST API 直接公开你的 JSON 对象来供客户端使用。此外,在从数据库读取或写入时(若是你使用的是MongoDB),你无需担忧在 JSON 和其余任何内容之间进行转换的问题。总之在客户端、服务器和数据库中使用统一的数据序列化格式,能够避免屡次转换的麻烦。

队列输入

若是你收到了大量并发数据,那么你的数据库可能会成为瓶颈。如上所述,Node.js 能够轻松地本身处理并发链接。可是由于数据库访问是一种阻塞操做(在这种状况下),因此咱们遇到了麻烦。解决方案是在数据真正写入数据库以前先确认客户端的行为。

经过这种方法,系统能够在高负载下保持其响应性,这在客户端不须要确认数据成功写入时尤为有用。典型的例子包括:记录或写入用户跟踪数据时进行分批处理;以及最终一致性(常常在NoSQL世界中使用)能够接受的不须要当即做出反映的操做(例如更新 Facebook 上的“Likes”计数)。

数据经过某种缓存或消息队列(例如,RabbitMQ,ZeroMQ)排队,并经过单独的数据库批量写入过程,或者由计算密集型后端服务进行消化,再写入更好的可以执行此类任务的平台。相似的行为能够用其余语言或框架实现,但不能在相同的硬件上实现,以维持相同的高吞吐量。

clipboard.png

简而言之:使用 Node,你能够将数据库写先入到一个地方,稍后再去处理它们,就像它们已经被成功处理同样。

数据流

在更传统的Web平台中,HTTP 请求和响应被看做是孤立事件,实际上他们是流。能够在 Node.js 中使用这个性质来构建一些很酷的功能。例如文件能够被一边上传一边处理,由于数据经过流进入,咱们能够实时的去处理它。这能够用于实时音频视频编码,以及在不一样数据源的之间进行代理(参见下一部分)。

代理

把 Node.js 用做服务器端代理是很容易的,它可以以非阻塞方式处理大量的并发链接。这对于为代理不一样响应时间的多个服务,或从多个源收集数据的场景特别有用。

例如如下场景:当服务器端程序与第三方资源进行通讯时,会从不一样的来源提取数据,或者将图像和视频等资源存储到第三方云服务上。

尽管有专用代理服务器,可是若是你没有基础的代理架构,或者你须要本地开发环境,那么 Node 可能会对你有所帮助。

股票交易商的数据界面

让咱们回到应用程序。能够很容易地用实时网络解决方案取代的另外一个例子是股票经纪人的交易软件,它用于跟踪股票价格、执行计算、技术分析以及建立图表。

若是切换到基于 Web 的实时解决方案,经纪人将能够轻松切换工做站或工做场所。很快,咱们可能会开始在佛罗里达州的海滩上看到它们......

应用监控仪表板

另外一个常见的用例,其中 Node-with-web-socket 彻底适合:跟踪网站访问者并对他们的交互进行实时的可视化。你能够从用户那里实时收集统计信息,甚至能够经过在访问渠道中特定的点来打开通讯渠道,并与访问者进行有针对性的互动,这种方案能够在这里找到: CANDDi

想象一下,若是你可以实时了解访问者所作的事情,你将如何改善你的业务呢?经过使用 Node.js 的实时双向套接字,如今就能够作到了。

系统监控仪表板

在基础设施方面,。好比想要为其用户提供服务监控页面的SaaS提供商(例如,GitHub状态页面)。经过 Node.js 事件循环,咱们能够建立一个功能强大的基于 Web 的仪表板,以异步方式检查服务的状态,并使用 websockets 将数据推送到客户端。公司内部和公共服务的状态均可以使用该技术获得实时报告。

注意:不要尝试在 Node.js 中构建硬实时系统(即须要一致响应时间的系统)。对于那类应用程序,Erlang 多是更好的选择

哪些场合可使用 Node.js

服务器端 Web 应用

配合 Express.js 的 Node.js 也可在服务器端建立经典 Web 应用。对于这种方法,有人支持也有人反对。如下是一些须要考虑的问题:

优势:

  • 若是你的程序没有任何 CPU 密集型计算,能够用 Javascript 和对象存储数据库(如MongoDB)构建它,甚至能够在数据库级别进行构建。这显著的简化了开发工做。
  • 爬虫会收到一个可以彻底呈现的 HTML 响应,这比单页应用或在 Node.js 上运行的 websockets 应用程序更能进行 SEO 。

缺点:

  • 任何 CPU 密集型计算都会阻止 Node.js 响应,所以线程平台是一种更好的方法。
  • 将 Node.js 与关系数据库放一块儿使用仍然很是困难(更多细节见下文)。若是你要对关系型数据库进行操做,请并选择 Rails、Django 或 ASP.Net MVC 等其余环境。

CPU 密集型计算的一种替代方法是建立一个可高度扩展的 MQ 支持环境,该环境具备后端处理功能,以使 Node 成为一个前台“职员”,并以异步方式处理客户端请求。

何时不该使用 Node.js

带有关系型数据库的服务器端 Web 应用

例如,将 Node.js + Express.js 与 Ruby on Rails 进行比较,当涉及到关系数据访问时,显而后者更合适。

与其竞争对手相比,Node.js 的关系型数据库工具仍然至关原始。另外一方面,Rails 提供了开箱即用的数据访问设置以及数据库架构迁移支持工具,另外还有其余的 Gems。 Rails 及相似框架拥有成熟的且通过验证的 Active RecordData Mapper 数据访问层实现,若是你想要尝试在纯 JavaScript 中复制这些功能的话,那么祝你好运。

不过,若是你真的倾向于用 JS 实现一切,请查看 SequelizeNode ORM2

若是仅仅是把 Node.js 用做面向公众的界面,同时用 Rails 后端访问关系数据库,这是能够的,并且这种方式并不罕见。

繁重的服务器端计算与处理

当涉及到繁重的计算时,Node.js 并非最好的平台。你绝对不想用 Node.js 去构建一个 Fibonacci 计算服务器。一般,任何 CPU 密集型操做都会经过事件驱动的非阻塞 I/O 模型来抵消 Node 提供的全部吞吐量优点,由于当线程被数字运算占用时,任何传入请求都将被阻止。

正如前面所说的,Node.js 是单线程的,只使用一个CPU核心。在多核服务器上添加并发性时,Node 核心团队以 cluster module 的形式完成一些工做。你也能够很容易地在反向代理 nginx 的后面运行几个 Node.js 服务器实例。

若是使用群集,你仍然应该将全部繁重的计算放到在更合适的环境下编写的后台进程中,并使它们经过像 RabbitMQ 这样的消息队列服务器进行通讯。

即便你全部的后台处理最初可能在同一服务器上运行,这种方法也有可能实现很是高的可伸缩性。这些后台处理服务能够轻松地被分发到单独的工做服务器,而无需对前置 Web 服务器负载进行配置。

固然,你也能够在其余平台上使用相同的方法,可是使用 Node.js,你能够得到咱们所讨论的高 reqs/sec 吞吐量,由于每一个请求都是一个很是快速有效的小任务。

结论

咱们讨论了 Node.js 从理论到实践,从它的目标和抱负开始,并以其最佳点和陷阱结束。当人们遇到 Node 的问题时,它几乎老是呗归结为阻塞操做是全部邪恶的根源 —— 其中 99% 的直接缘由是对 Node 的误用。

请记住:不要用 Node.js 来解决计算扩展问题。它是为了解决 I/O 扩展问题而设计的,它作得确实很好

因此,若是你的应用不包含 CPU 密集型操做,也不访问任何阻塞资源的话,能够利用 Node.js 的优点,享受快速、可扩展的网络应用。


本文首发微信公众号:前端先锋

未经许可,禁止转载!

欢迎扫描二维码关注公众号,天天都给你推送新鲜的前端技术文章

欢迎扫描二维码关注公众号,天天都给你推送新鲜的前端技术文章


欢迎继续阅读本专栏其它高赞文章:


相关文章
相关标签/搜索