概述:

  NodeJS宣称其目标是“旨在提供一种简单的构建可伸缩网络程序的方法”,那么它的出现是为了解决什么问题呢,它有什么优缺点以及它适用于什么场景呢?

  本文就个人使用经验对这些问题进行探讨。

一. NodeJS的特点

  我们先来看看NodeJS官网上的介绍:

  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. 单进程,单线程

二. NodeJS带来的对系统瓶颈的解决方案

  它的出现确实能为我们解决现实当中系统瓶颈提供了新的思路和方案,下面我们看看它能解决什么问题

  1. 并发连接

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

  (1)系统线程模型:

  

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

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

  

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

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

  

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

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

  那么NodeJS是怎么解决这个问题的呢?

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

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

  

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

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

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

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

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

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

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

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

  

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

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

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

  2. I/O阻塞

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

  (1)串行获取数据,这是我们一般的解决方案,以PHP为例

  

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

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

  

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

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

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

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

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

  总结一下:

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

三. NodeJS的优缺点

  优点:

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

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

    缺点:

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

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

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

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

    原因:单进程,单线程

    解决方案:(1)Nnigx反向代理,负载均衡,开多个进程,绑定多个端口;

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

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

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

四. 适合NodeJS的场景

  1. RESTful API

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

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

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

  2. 统一Web应用的UI层

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

  

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

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

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

  

  3. 大量Ajax请求的应用

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

  NodeJS能响应大量的并发请求

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

五. 结尾

  其实NodeJS能实现几乎一切的应用

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

六. 参考文献

  [1] Node.js能构建支持并发和高负载的大型应用吗?

  [2] 理解Node.js事件驱动编程

  [3] 是否不擅长CPU密集型业务

  [4] 使用 Node.js 的优势和劣势都有哪些?有大公司用吗?

  [5] Node.js给前端带来了什么

[NodeJS] 优缺点及适用场景讨论的更多相关文章

  1. NodeJS优缺点及适用场景讨论

    概述:NodeJS宣称其目标是“旨在提供一种简单的构建可伸缩网络程序的方法”,那么它的出现是为了解决什么问题呢,它有什么优缺点以及它适用于什么场景呢? 本文就个人使用经验对这些问题进行探讨. 一. N ...

  2. [转载]NodeJS优缺点及适用场景讨论

    http://www.xprogrammer.com/159.html 概述:NodeJS宣称其目标是“旨在提供一种简单的构建可伸缩网络程序的方法”,那么它的出现是为了解决什么问题呢,它有什么优缺点以 ...

  3. [NodeJS] 优缺点及适用场景

    概述: NodeJS宣称其目标是“旨在提供一种简单的构建可伸缩网络程序的方法”,那么它的出现是为了解决什么问题呢,它有什么优缺点以及它适用于什么场景呢? 本文就个人使用经验对这些问题进行探讨. 一. ...

  4. Ajax原理、优缺点及应用场景

    前言 Ajax的全称为Asynchronous JavaScript And Xml,是一种web客户端与服务器端异步通信的技术,如今,可以说是web开发人员必须掌握的的一项技能了.本文讲述了Ajax ...

  5. JS中lambda表达式的优缺点和使用场景(转)

    add by zhj: 最近在看ES6,看到了箭头函数,我个人感觉箭头函数适用于函数体中不用this的匿名函数,在箭头函数中使用this是一个坑 原文:http://ourjs.com/detail/ ...

  6. SSH框架阶段 ——SSH的优缺点,使用场景?

    Hibernate优点: (1) 对象/关系数据库映射(ORM)它使用时只需要操纵对象,使开发更对象化,抛弃了数据库中心的思想,完全的面向对象思想(2) 透明持久化(persistent)带有持久化状 ...

  7. c#中的var优缺点和适用场景

    var是c# 3.0新加的特性,叫做隐式类型局部变量,大家都知道c#其实是一种强类型的语言,为什么会引入匿名类型呢? 我猜测是因为linq的原因吧,因为感觉var在linq中被大量使用.下面说下var ...

  8. AngularJS优缺点、使用场景

    AngularJS 优缺点 优点: AngularJS模板功能强大丰富,自带了极其丰富的angular指令. AngularJS是完全可扩展的,与其他库的兼容效果很好,每一个功能可以修改或更换,以满足 ...

  9. Kafka leader副本选举与消息丢失场景讨论

    如果某个broker挂了,leader副本在该broker上的分区就要重新进行leader选举.来简要描述下leader选举的过程 1.4.1 KafkaController会监听ZooKeeper的 ...

随机推荐

  1. Network Basic Commands Summary

    Network Basic Commands Summary set or modify hostname a)     temporary ways hostname NEW_HOSTNAME, b ...

  2. 为什么我如此热爱这样一个比赛(转自vici)

    为什么我如此的热爱这样一个比赛呢?因为它总能带给我一个目标,让我去努力实现它.因为可以看到胜利的希望,于是不断的去追逐.虽然其中的过程可能是比较艰辛的.   对于天才选手,作为天生的冠军,大概凭借天赋 ...

  3. vim中 set 用法设置

    vi set用法from google search一.常用收集如下:(vi set)set autoindent     在插入模式下,对每行按与上行同样的标准进行缩进,与shiftwidth选项结 ...

  4. 计算机病毒实践汇总六:IDA Pro基础

    在尝试学习分析的过程中,判断结论不一定准确,只是一些我自己的思考和探索.敬请批评指正! 1. IDA使用 (1)搜索.下载并执行IDA Pro,对可执行程序lab05-01.dll进行装载,分别以图形 ...

  5. c# nullable类型有什么用

    可空类型,语法: ;            int? inully = 10; Nullable<int> inullx0 = null;            int? inully0 ...

  6. mysql查询所有表行数

    SELECT table_name, table_rows FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'DATABASE_NAME' ;

  7. ***PHP中empty()和isset()的区别

    对于初学php的人来说,empty()和和isset()用法的区别是很难搞清楚的,他们的用法的差别不仔细去琢磨的话确实很难弄清楚. 先说一下他们的共同点: 都可以判定一个变量是否为空: 都返回bool ...

  8. android Activity的启动模式与flag的见解

    最近做一个安卓项目,想要实现的效果就是:当打开一个按钮的时候,启动了一个A功能,当用户返回到桌面再继续进去的时候,不过之前在哪个Activity,都会先跳转到A功能的那个界面,当用户点击返回的时候,再 ...

  9. Creating, Stopping, Re-Starting and Deleting a Timer in Oracle Forms

    I have written many posts previously on Timers in Oracle Forms like how to change images randomly wi ...

  10. HTTP方法简介

    GET 请求获取资源 HEAD 与GET类似,但服务器只返回首部 PUT 与GET相反,向服务器写入文档 POST 向服务器输入数据,通常使用HTML表单形式 TRACE 客户端发起请求时,需要穿越防 ...