为什么我会使用Node.js(个案教程)

本文概述

  • 介绍
  • 它是如何工作的?
  • NPM:节点程序包管理器
  • 应该在哪里使用Node.js的示例
  • 可以在哪里使用Node.js
  • 不应该使用Node.js的地方
  • 总结
介绍 JavaScript的日益普及带来了许多变化, 并且当今的Web开发面貌截然不同。如今, 我们可以在服务器和浏览器上运行JavaScript的情况下, 如今在Web上做的事情在几年前还很难想象, 或者封装在Flash或Java Applets之类的沙盒环境中。
在深入研究Node.js解决方案之前, 你可能需要阅读在整个堆栈上使用JavaScript的好处, 它可以统一语言和数据格式(JSON), 从而使你能够最佳地重用开发人员资源。由于JavaScript比Node.js更能带来JavaScript的好处, 因此我们在这里不再赘述。但这是将Node集成到堆栈中的主要优势。
正如Wikipedia所言:” Node.js是Google V8 JavaScript引擎, libuv平台抽象层和核心库的打包编译, 该库本身主要是用JavaScript编写的。” 除此之外, 值得注意的是, Node.js的创建者Ryan Dahl旨在创建具有推送功能的实时网站, “ 受Gmail等应用程序的启发” 。在Node.js中, 他为开发人员提供了一种用于非阻塞, 事件驱动的I / O范例的工具。
经过20多年基于无状态请求-响应范例的无状态Web, 我们终于有了具有实时双向连接的Web应用程序。
【为什么我会使用Node.js(个案教程)】一句话:Node.js在通过Websockets上采用推技术的实时Web应用程序中脱颖而出。那有什么革命呢?好了, 经过20多年基于无状态请求-响应范式的无状态Web, 我们终于有了具有实时双向连接的Web应用程序, 客户端和服务器都可以发起通信, 从而允许他们自由交换数据。这与典型的Web响应范例形成鲜明对比, 在典型的Web响应范例中, 客户端始终启动通信。此外, 它们全部基于在标准端口80上运行的开放式网络堆栈(HTML, CSS和JS)。
有人可能会争辩说, 我们已经以Flash和Java Applet的形式存在了很多年, 但实际上, 这些只是沙盒环境, 使用Web作为要传输到客户端的传输协议。另外, 它们是独立运行的, 通常在非标准端口上运行, 这些端口可能需要额外的权限等等。
凭借其所有优势, Node.js现在在许多依靠其独特优势的知名公司的技术堆栈中扮演着至关重要的角色。 Node.js基金会在Node.js Foundation的” 案例研究” 页面上的简短演示中, 汇总了有关企业为何应考虑Node.js的所有最佳思路。
在本Node.js指南中, 我不仅将以一些经典的Web应用程序模型为例, 讨论如何实现这些优势, 以及为什么要使用Node.js以及为什么不希望使用Node.js。
它是如何工作的? Node.js的主要思想是:使用非阻塞的, 事件驱动的I / O可以在跨分布式设备运行的数据密集型实时应用程序中保持轻巧高效。
满嘴
它的真正含义是, Node.js并不是一个支配Web开发世界的全新项目。相反, 它是一个满足特定需求的平台。
鸣叫
它的真正含义是, Node.js并不是一个支配Web开发世界的全新项目。相反, 它是一个满足特定需求的平台。理解这一点绝对至关重要。你绝对不希望使用Node.js进行CPU密集型操作;实际上, 将其用于繁重的计算将几乎消除其所有优势。 Node真正的亮点在于构建快速, 可扩展的网络应用程序, 因为它能够处理大量并发连接并具有高吞吐量, 这相当于高可扩展性。
它的工作原理非常有趣。与传统的Web服务技术(每个连接(请求)产生一个新线程, 占用系统RAM并最终以可用的RAM数量最大化)相比, Node.js使用非阻塞I / O在单线程上运行O调用, 使其支持事件循环中保存的成千上万的并发连接。
为什么我会使用Node.js(个案教程)

文章图片
快速计算:假设每个线程可能都带有2 MB的伴随内存, 并在具有8 GB RAM的系统上运行, 则理论上我们最多可以有4, 000个并发连接(计算取自Michael Abernethy的文章” Just is Node” ) ” .js?” , 于2011年在IBM developerWorks上发布;不幸的是, 该文章不再可用), 加上线程之间上下文切换的成本。这就是你通常在传统网络服务技术中遇到的情况。通过避免所有这些, Node.js实现了超过1M的并发连接和超过60万的并发Websocket连接的可伸缩性级别。
当然, 在所有客户端请求之间共享一个线程是一个问题, 这是编写Node.js应用程序的潜在陷阱。首先, 繁重的计算可能会阻塞Node的单线程, 并给所有客户端造成问题(稍后会详细介绍), 因为传入请求将被阻止, 直到完成计算为止。其次, 开发人员需要非常小心, 不要让异常冒泡到核心(最顶层)Node.js事件循环, 这将导致Node.js实例终止(有效地使程序崩溃)。
避免异常冒泡到表面的技术是将错误作为回调参数传递给调用者(而不是像在其他环境中一样抛出错误)。即使某些未处理的异常得以解决, 也已经开发了工具来监视Node.js进程并执行崩溃实例的必要恢复(尽管你可能无法恢复用户会话的当前状态), 最常见的是Forever模块, 或者对外部系统工具使用新的方法upstart和monit, 甚至只是upstart。
NPM:节点程序包管理器 在讨论Node.js时, 绝对不应该忽略的一件事是使用NPM对程序包管理的内置支持, NPM是每个Node.js安装默认提供的工具。 NPM模块的思想与Ruby Gems的思想非常相似:一组公开可用, 可重用的组件, 可以通过在线存储库中的易于安装的版本和依赖项管理来获得。
打包模块的完整列表可以在npm网站上找到, 也可以使用随Node.js自动安装的npm CLI工具进行访问。模块生态系统向所有人开放, 任何人都可以发布自己的模块, 该模块将在npm存储库中列出。
当今一些最有用的npm模块是:
  • express-Express.js(或简称Express)是一个受Sinatra启发的Node.js Web开发框架, 以及当今大多数Node.js应用程序的实际标准。
  • hapi-一个非常模块化且易于使用的以配置为中心的框架, 用于构建Web和服务应用程序
  • connect-Connect是用于Node.js的可扩展HTTP服务器框架, 提供了称为中间件的高性能” 插件” 的集合;作为Express的基础。
  • socket.io和sockjs-当今最常见的两个websockets组件的服务器端组件。
  • pug(以前称为Jade)-受HAML(Express.js中的默认设置)启发而流行的模板引擎之一。
  • mongodb和mongojs-MongoDB包装器, 用于在Node.js中为MongoDB对象数据库提供API。
  • redis-Redis客户端库。
  • lodash(下划线, lazy.js)-JavaScript实用程序带。 Underscore发起了该游戏, 但由于性能和模块化实施方面的优势而被其两个对手之一推翻。
  • 永远-可能是确保给定节点脚本连续运行的最常用工具。遇到任何意外故障时, 可以使你的Node.js流程保持在生产中。
  • bluebird-功能齐全的Promises / A +实现, 具有出色的性能
  • moment-用于解析, 验证, 操作和格式化日期的JavaScript日期库。
清单继续。那里有很多真正有用的软件包, 可供所有人使用(对于我在这里省略的软件包没有冒犯)。
应该在哪里使用Node.js的示例 聊天
聊天是最典型的实时, 多用户应用程序。从IRC(在过去)到通过在非标准端口上运行的许多专有和开放协议, 到能够通过标准端口80上运行的websocket在Node.js中实现当今的所有功能。
聊天应用程序确实是Node.js的最佳示例:它是一个轻量级, 高流量, 数据密集型(但处理/计算量低)的应用程序, 可在分布式设备上运行。它很简单, 也是学习的好用例, 但它涵盖了你在典型的Node.js应用程序中将使用的大多数范例。
让我们来描述一下它是如何工作的。
在最简单的示例中, 我们在网站上设有一个聊天室, 人们可以来此聊天室, 并且可以一对多(实际上是全部)方式交换消息。例如, 假设我们网站上有三个人都连接到我们的留言板。
在服务器端, 我们有一个简单的Express.js应用程序, 该应用程序实现了两件事:
  1. 一个GET /请求处理程序, 该程序为包含留言板和” 发送” 按钮的网页提供服务, 以初始化新的消息输入, 以及
  2. 一个Websockets服务器, 用于侦听Websocket客户端发出的新消息。
在客户端, 我们有一个HTML页面, 其中设置了两个处理程序, 一个用于” 发送” 按钮单击事件, 该处理程序拾取输入消息并将其发送到websocket, 然后另一个侦听新的传入消息在websockets客户端上(即, 其他用户发送的消息, 服务器现在希望客户端显示)。
当其中一位客户发布消息时, 会发生以下情况:
  1. 浏览器通过JavaScript处理程序捕获” 发送” 按钮的点击, 从输入字段中获取值(即消息文本), 并使用连接到我们服务器的websocket客户端发出websocket消息(在网页初始化时初始化)。
  2. Websocket连接的服务器端组件接收消息, 并使用广播方法将其转发给所有其他连接的客户端。
  3. 所有客户端都通过运行在网页内的websockets客户端组件以推送消息的形式接收新消息。然后, 他们获取消息内容并通过将新消息附加到面板上来就地更新网页。
为什么我会使用Node.js(个案教程)

文章图片
这是最简单的例子。对于更强大的解决方案, 你可以使用基于Redis存储的简单缓存。甚至在更高级的解决方案中, 还有一个消息队列(用于处理将消息路由到客户端的消息)和更强大的传递机制, 该机制可以弥补临时连接丢失或为注册客户端离线时存储的消息提供便利。但是, 不管你进行了哪些改进, Node.js仍将按照相同的基本原则进行操作:对事件做出反应, 处理许多并发连接以及保持用户体验的流畅性。
对象数据库顶部的API
尽管Node.js确实在实时应用程序中大放异彩, 但它很自然地适合公开对象数据库(例如MongoDB)中的数据。 JSON存储的数据允许Node.js正常运行, 而不会出现阻抗不匹配和数据转换的情况。
例如, 如果你使用的是Rails, 则将数据从JSON转换为二进制模型, 然后当数据被Backbone.js, Angular.js等甚至普通的jQuery AJAX占用时, 通过HTTP将其公开为JSON。电话。使用Node.js, 你可以简单地使用REST API公开JSON对象, 以供客户端使用。此外, 从数据库读取或写入数据时(如果使用的是MongoDB), 你无需担心在JSON与其他任何内容之间进行转换。总之, 通过在客户端, 服务器和数据库之间使用统一的数据序列化格式, 可以避免多次转换的需要。
排队的输入
如果你收到大量并发数据, 则数据库可能会成为瓶颈。如上所述, Node.js可以轻松处理并发连接本身。但是因为数据库访问是阻塞操作(在这种情况下), 所以我们遇到了麻烦。解决方案是在将数据真正写入数据库之前, 先确认客户的行为。
使用这种方法, 系统可以在高负载下保持其响应速度, 这在客户端不需要确定成功写入数据的客户端时特别有用。典型示例包括:记录或写入用户跟踪数据, 分批处理, 直到以后才使用;以及不需要立即反映出来的操作(例如更新Facebook上的” 喜欢” 计数), 并且可以接受最终的一致性(在NoSQL世界中经常使用)。
数据通过某种缓存或消息排队基础结构(例如RabbitMQ或ZeroMQ)排队, 并由一个单独的数据库批处理过程或计算密集型处理后端服务进行摘要, 并以性能更好的平台编写用于此类任务。可以使用其他语言/框架来实现类似的行为, 但不能在具有相同的高维护吞吐量的相同硬件上实现。
为什么我会使用Node.js(个案教程)

文章图片
简而言之:使用Node, 你可以将数据库写入推迟到一边, 然后稍后再处理, 就好像它们成功了一样。
数据流
在更传统的Web平台中, HTTP请求和响应被视为独立事件。实际上, 它们实际上是流。可以在Node.js中利用此观察结果来构建一些很酷的功能。例如, 由于数据是通过流输入的, 因此可以在文件仍处于上传状态时对其进行处理, 而我们可以以在线方式对其进行处理。这可以用于实时音频或视频编码, 以及在不同数据源之间进行代理(请参阅下一部分)。
代理
Node.js易于用作服务器端代理, 在其中它可以以非阻塞方式处理大量同时连接。在代理具有不同响应时间的不同服务或从多个源点收集数据时特别有用。
例如:考虑一个服务器端应用程序与第三方资源进行通信, 从不同来源提取数据或将诸如图像和视频之类的资产存储到第三方云服务中。
尽管确实存在专用的代理服务器, 但是如果不存在代理基础结构或需要本地开发解决方案, 则使用Node可能会有所帮助。我的意思是, 你可以使用Node.js开发服务器来构建客户端应用程序, 以处理资产和代理/存根API请求, 而在生产中, 你将通过专用代理服务(nginx, HAProxy等)处理此类交互)。
经纪-股票交易者的控制板
让我们回到应用程序级别。台式机软件占主导地位但可以很容易地被实时Web解决方案取代的另一个例子是经纪人的交易软件, 用于跟踪股票价格, 执行计算/技术分析以及创建图表/图表。
切换到基于Web的实时解决方案将使经纪人可以轻松地切换工作站或工作场所。很快, 我们可能会开始在佛罗里达州..伊维萨岛..或巴厘岛的海滩上看到它们。
应用监控仪表板
带有网络套接字的节点非常适合的另一个常见用例:跟踪网站访问者并实时可视化其交互。
你可以从用户那里收集实时统计信息, 甚至可以通过在访问者到达渠道中的特定点时打开交流渠道来引入与访问者的定向互动, 从而将其转移到下一个层次。 (如果你有兴趣, 则CANDDi已将这种想法付诸实践。)
想象一下, 如果你可以实时了解访问者的行为, 并且可以可视化他们的互动, 那么如何改善业务。现在可以使用Node.js的实时双向套接字。
系统监控仪表板
现在, 让我们来看一下基础架构方面的内容。例如, 想象一下一个SaaS提供商想要为其用户提供服务监视页面, 例如GitHub的状态页面。借助Node.js事件循环, 我们可以创建一个基于Web的强大仪表板, 该仪表板以异步方式检查服务的状态, 并使用websocket将数据推送到客户端。
内部(公司内部)和公共服务的状态都可以使用此技术实时报告。进一步推动这个想法, 并尝试想象一个网络运营中心(NOC)监视电信运营商, 云/网络/托管提供商或某些金融机构中的应用程序, 它们都在由Node.js和websockets支持的开放Web堆栈上运行而不是Java和/或Java Applet。
注意:请勿尝试在Node中构建硬实时系统(即要求一致响应时间的系统)。对于此类应用程序, Erlang可能是更好的选择。
可以在哪里使用Node.js 服务器端Web应用程序
Node.js和Express.js还可用于在服务器端创建经典的Web应用程序。但是, 尽管可能, 但Node.js将随身携带渲染HTML的这种请求-响应范例并不是最典型的用例。对于这种方法, 有很多论点可以支持和反对。以下是一些要考虑的事实:
优点:
  • 如果你的应用程序不进行任何CPU密集型计算, 则可以使用Java脚本从上到下进行构建, 甚至在使用JSON存储对象数据库(如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进行比较, 在访问关系数据库(如PostgreSQL, MySQL和Microsoft SQL Server)时, 曾经有一个明确的决定支持后者。
用于Node.js的关系数据库工具仍处于早期阶段。另一方面, Rails会立即自动提供数据访问设置以及DB模式迁移支持工具和其他Gems(双关语)。 Rails及其对等框架具有成熟可靠的Active Record或Data Mapper数据访问层实现。[*]
但是情况已经变了。 Sequelize, TypeORM和Bookshelf在成为成熟的ORM解决方案方面已经走了很长一段路。如果你想从GraphQL查询中生成SQL, 也可能值得一试。
[*]仅将Node用作前端, 同时保持Rails后端及其对关系数据库的轻松访问, 这是可能的, 并且很常见。
相关:后端:使用Gatsby.js和Node.js进行静态网站更新
大量的服务器端计算/处理
在进行大量计算时, Node.js并不是最好的平台。不, 你绝对不想在Node.js中构建Fibonacci计算服务器。通常, 任何占用大量CPU的操作都会废除Node通过其事件驱动的非阻塞I / O模型提供的所有吞吐量优势, 因为在线程被数字运算占用的同时, 任何传入的请求都将被阻塞(假设你正在尝试)在你响应请求的同一Node实例中运行计算。
如前所述, Node.js是单线程的, 并且仅使用单个CPU内核。当涉及到在多核服务器上增加并发性时, Node核心团队正在以集群模块的形式进行一些工作[参考:http://nodejs.org/api/cluster.html]。你还可以通过nginx在反向代理后面很容易地运行多个Node.js服务器实例。
通过集群, 你仍应将所有繁重的计算工作卸载到在更合适的环境中编写的后台进程中进行, 并使其通过RabbitMQ之类的消息队列服务器进行通信。
即使你的后台处理最初可能在同一台服务器上运行, 这种方法仍具有很高的可伸缩性。这些后台处理服务可以轻松地分发到单独的工作服务器, 而无需配置前端Web服务器的负载。
当然, 你也可以在其他平台上使用相同的方法, 但是通过Node.js, 你可以获得我们所谈论的高reqs / sec吞吐量, 因为每个请求都是非常快速有效地处理的小任务。
总结 我们已经从理论到实践讨论了Node.js, 从它的目标和野心开始, 到它的甜蜜点和陷阱。当人们遇到Node问题时, 几乎总可以归结为阻塞操作是万恶之源的事实-99%的Node滥用是直接后果。
在Node中, 阻塞操作是万恶之源-99%的Node滥用是直接后果。
鸣叫
请记住:从未创建Node.js来解决计算扩展问题。创建它是为了解决I / O扩展问题, 它确实做得很好。
为什么要使用Node.js?如果你的用例不包含CPU密集型操作, 也不访问任何阻塞资源, 则可以利用Node.js的好处, 并享受快速且可扩展的网络应用程序。欢迎来到实时网络。

    推荐阅读