Node.js 优缺点及适用场景讨论

Node.js 不是 JS 应用、而是 JS 运行平台

看到 Node.js 这个名字,初学者可能会误以为这是一个 Javascript 应用,事实上,Node.js 采用 C++ 语言编写而成,是一个 Javascript 的运行环境。为什么采用 C++ 语言呢?据 Node.js 创始人 Ryan Dahl 回忆,他最初希望采用 Ruby 来写 Node.js,但是后来发现 Ruby 虚拟机的性能不能满足他的要求,后来他尝试采用 V8 引擎,所以选择了 C++ 语言。既然不是 Javascript 应用,为何叫 .js 呢?因为 Node.js 是一个 Javascript 的运行环境。提到 Javascript,大家首先想到的是日常使用的浏览器,现代浏览器包含了各种组件,包括渲染引擎、Javascript 引擎等,其中 Javascript 引擎负责解释执行网页中的 Javascript 代码。作为 Web 前端最重要的语言之一,Javascript 一直是前端工程师的专利。不过,Node.js 是一个后端的 Javascript 运行环境(支持的系统包括 Linux、Windows),这意味着你可以编写系统级或者服务器端的 Javascript 代码,交给 Node.js 来解释执行。

Node.js 采用了 Google Chrome 浏览器的 V8 引擎,性能很好,同时还提供了很多系统级的 API,如文件操作、网络编程等。浏览器端的 Javascript 代码在运行时会受到各种安全性的限制,对客户系统的操作有限。相比之下,Node.js 则是一个全面的后台运行时,为 Javascript 提供了其他语言能够实现的许多功能。

Node.js 的特点

我们先来看看 Node.js 官网上的介绍:

Node.js is a platform built on Chrome's JavaScript runtime for easily building fast, scalable network applications. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, perfect for data-intensive real-time applications that run across distributed devices.

其特点为:

  1. 它是一个 Javascript 运行环境

  2. 依赖于 Chrome V8 引擎进行代码解释

  3. 事件驱动

  4. 非阻塞 I/O

  5. 轻量、可伸缩,适于实时数据交互应用

  6. 单进程,单线程

Node.js 带来的对系统瓶颈的解决方案

1. 并发连接

举个例子,想象一个场景,我们在银行排队办理业务,我们看看下面两个模型

(1)系统线程模型:

这种模型的问题显而易见,服务端只有一个线程,并发请求(用户)到达只能处理一个,其余的要先等待,这就是阻塞,正在享受服务的请求阻塞后面的请求了

(2)多线程、线程池模型:

这个模型已经比上一个有所进步,它调节服务端线程的数量来提高对并发请求的接收和响应,但并发量高的时候,请求仍然需要等待,它有个更严重的问题:

回到代码层面上来讲,我们看看客户端请求与服务端通讯的过程:

服务端与客户端每建立一个连接,都要为这个连接分配一套配套的资源,主要体现为系统内存资源,以 PHP 为例,维护一个连接可能需要 20M 的内存

这就是为什么一般并发量一大,就需要多开服务器

那么 Node.js 是怎么解决这个问题的呢?

我们来看另外一个模型,想象一下我们在快餐店点餐吃饭的场景

(3)异步、事件驱动模型

我们同样是要发起请求,等待服务器端响应;但是与银行例子不同的是,这次我们点完餐后拿到了一个号码,

拿到号码,我们往往会在位置上等待,而在我们后面的请求会继续得到处理,同样是拿了一个号码然后到一旁等待,接待员能一直进行处理。

等到饭菜做号了,会喊号码,我们拿到了自己的饭菜,进行后续的处理(吃饭)

这个喊号码的动作在 Node.js 中叫做回调(Callback),能在事件(烧菜,I/O)处理完成后继续执行后面的逻辑(吃饭),

这体现了 Node.js 的显著特点,异步机制、事件驱动

整个过程没有阻塞新用户的连接(点餐),也不需要维护已经点餐的用户与厨师的连接

基于这样的机制,理论上陆续有用户请求连接, Node.js 都可以进行响应,因此 Node.js 能支持比Java、PHP程序更高的并发量

虽然维护事件队列也需要成本,再由于 Node.js 是单线程,事件队列越长,得到响应的时间就越长,并发量上去还是会力不从心

总结一下 Node.js 是怎么解决并发连接这个问题的:

更改连接到服务器的方式,每个连接发射(emit)一个在 Node.js 引擎进程中运行的事件(Event),放进事件队列当中,

而不是为每个连接生成一个新的 OS 线程(并为其分配一些配套内存)

2. I/O 阻塞

Node.js 解决的另外一个问题是 I/O 阻塞,看看这样的业务场景:需要从多个数据源拉取数据,然后进行处理

(1)串行获取数据

这是我们一般的解决方案,以 PHP 为例

假如获取 profile 和 timeline 操作各需要 1s,那么串行获取就需要 2s

(2) Node.js 非阻塞 I/O,发射/监听事件来控制执行过程

Node.js 遇到 I/O 事件会创建一个线程去执行,然后主线程会继续往下执行的

因此,拿 profile 的动作触发一个 I/O 事件,马上就会执行拿 timeline 的动作

两个动作并行执行,假如各需要 1s,那么总的时间也就是 1s

它们的I/O操作执行完成后,发射一个事件,profile和timeline

事件代理接收后继续往下执行后面的逻辑,这就是 Node.js 非阻塞I/O的特点

总结一下:

Java、PHP 也有办法实现并行请求(子线程),但 Node.js 通过回调函数(Callback)和异步机制会做得很自然

Node.js 的优缺点

优点:

  1. 高并发(最重要的优点)

  2. 适合 I/O 密集型应用

缺点:

  1. 不适合 CPU 密集型应用;CPU 密集型应用给 Node 的挑战主要是:由于JavaScript 单线程的原因,如果有长时间运行的计算(比如大循环),将会导致 CPU 时间片不能释放,使得后续 I/O 发起;

解决方案:分解大型运算任务为多个小任务,使得运算能够适时释放,不阻塞 I/O 调用的发起;

  1. 只支持单核 CPU,不能充分利用 CPU

  2. 可靠性低,一旦代码某个环节崩溃,整个系统都崩溃

原因:单进程,单线程

解决方案:

(1)Nginx 反向代理,负载均衡,开多个进程,绑定多个端口;

(2)开多个进程监听同一个端口,使用 cluster 模块;

  1. 开源组件库质量参差不齐,更新快,向下不兼容

  2. Debug 不方便,错误没有 stack trace

适合 Node.js 的场景

1. RESTful API

这是 Node.js 最理想的应用场景,可以处理数万条连接,本身没有太多的逻辑,只需要请求API,组织数据进行返回即可。

它本质上只是从某个数据库中查找一些值并将它们组成一个响应。

由于响应是少量文本,入站请求也是少量的文本,因此流量不高,一台机器甚至也可以处理最繁忙的公司的 API 需求。

2. 统一 Web 应用的 UI 层

目前 MVC 的架构,在某种意义上来说,Web 开发有两个 UI 层,一个是在浏览器里面我们最终看到的,另一个在 server 端,负责生成和拼接页面。

不讨论这种架构是好是坏,但是有另外一种实践,面向服务的架构,更好的做前后端的依赖分离。

如果所有的关键业务逻辑都封装成 REST 调用,就意味着在上层只需要考虑如何用这些 REST 接口构建具体的应用。

那些后端程序员们根本不操心具体数据是如何从一个页面传递到另一个页面的,他们也不用管用户数据更新是通过 Ajax 异步获取的还是通过刷新页面

3. 大量 Ajax 请求的应用

例如个性化应用,每个用户看到的页面都不一样,缓存失效,需要在页面加载的时候发起 Ajax 请求

Node.js 能响应大量的并发请求

总而言之, Node.js 适合运用在高并发、I/O 密集、少量业务逻辑的场景

结尾

其实 Node.js 能实现几乎一切的应用

我们考虑的点只是适不适合用它来做

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,013评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,205评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,370评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,168评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,153评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,954评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,271评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,916评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,382评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,877评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,989评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,624评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,209评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,199评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,418评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,401评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,700评论 2 345

推荐阅读更多精彩内容

  • topics: 1.The Node.js philosophy 2.The reactor pattern 3....
    宫若石阅读 1,057评论 0 1
  • [NodeJS] 优缺点及适用场景讨论 概述: NodeJS宣称其目标是“旨在提供一种简单的构建可伸缩网络程序的方...
    笑极阅读 9,135评论 1 23
  • 概述:NodeJS宣称其目标是“旨在提供一种简单的构建可伸缩网络程序的方法”,那么它的出现是为了解决什么问题呢,它...
    weihuafang阅读 659评论 0 2
  • 1.认识她,认为她是我的好朋友有八年多了 2.分享彼此的秘密,讨论过各种私密的话题 3.一起出去旅行过 4.一起听...
    涂山莘莘阅读 264评论 0 1
  • 看着自己不及格的英语成绩 想着那个时候,自己学英语超用功的。 看着自己日渐松弛的肌肉的肚子 想着那个时候,我天天锻...
    钟独阅读 188评论 0 2