nodeJS Basic程序员

带你领略Nodejs前世今生

2017-07-12  本文已影响325人  simuty

目录

目录

第一部分 网络编程策略演进

1.1 C10k的解决与新技术的产生

上世纪90年代提出了一个著名的C10k问题

image.png

大概意思是当用户数超过1万时,很多没设计好的网络服务程序性能将急剧下降,甚至瘫痪。这时候升级硬件也不管用了,问题的根源是系统处理请求的策略,有再多的硬件资源它也用不起来。后来人们总结出了四种典型的网络编程策略

1. 服务器为每个客户端请求分配一个线程/进程,使用阻塞式I/O。Java就是这种策略,Apache也是,这种策略还是很多交互式应用的首选。因为阻塞,这种策略很难实现高性能,但非常简单,可以实现复杂的交互逻辑。
2. 服务器用一个线程处理所有客户端请求,使用非阻塞的I/O及事件机制。node.js采用的就是这种策略。这种策略实现起来比较简单,方便移植,也能提供足够的性能,但无法充分利用多核CPU资源。
3. 服务器会分配多个线程来处理请求,但每个线程只处理其中一组客户端的请求,使用非阻塞的I/O及事件机制。这是对第二种策略的简单改进,在多线程并发上容易出现bug。
4. 服务器会分配多个线程来处理请求,但每个线程只处理其中一组客户端的请求,使用异步I/O。这种策略在支持异步I/O的操作系统上性能非常高,但实现起来很难,主要用在windows平台上。

既然有了C10K问题,程序员们就开始行动去解决它。于是FreeBSD推出了kqueueLinux推出了epoll,Windows推出了IOCP。这些操作系统提供的功能就是为了解决C10K问题。因为Linux是互联网企业中使用率最高的操作系统,Epoll就成为C10K killer、高并发、高性能、异步非阻塞这些技术的代名词了。

epoll技术的编程模型就是异步非阻塞回调,也可以叫做Reactor,事件驱动,事件轮循(EventLoop)。Epoll就是为了解决C10K问题而生。使用Epoll技术,使得小公司也可以玩高并发。不需要购买很多服务器,有几台服务器就可以服务大量用户。Nginxlibeventnode.js这些就是Epoll时代的产物

1.2 协成/异步回调

Epoll既然能解决C10K,解决什么C100K,C1M也是可以的。多买几个服务器就行了。
Node.js层层回调,缩进了几十层,要把程序员逼疯了。于是一个新的技术被提出来了,那就是协程(coroutine)。本质上也是异步非阻塞技术,它是将事件回调进行了包装,让程序员看不到里面的事件循环。【协程是异步非阻塞的另外一种展现形式】。

这个就像时间禁止的游戏一样,国王对巫师说“我必须马上得到宝物,不然就砍了你的脑袋”,巫师念了一句时间停止的咒语,直到过了1年后勇士们才把宝物送来。这时候巫师解开咒语,把宝物交给国王。这里国王就可以理解成协程,他根本没感觉到时间停止,在他停止到醒来期间发生了什么他不知道,也不关心。

异步回调与协程对比、协成与同步阻塞对比,请参阅关于C10K、异步回调、协程、同步阻塞

第二部分 Nodejs诞生

不要惹辍学生,分分钟给你发个Offer!
不要惹程序员,分分钟给你来个新花样!

大佬们为了改变世界,爆发出满满的负能量,也是操碎了❤️的。这不就是下边这哥们--【Ryan Dahl】,真是不服就干!

image.png

2.1 这碗鸡血我咽不下。。

Ryan Dahl的经历比较【奇特】,他并非科班出身的开发者,在2004年的时候他还在纽约的罗彻斯特大学数学系读博士,期间有研究一些分形、分类以及p-adic分析,这些都跟开源和编程没啥关系。
2006年,也许是厌倦了读博的无聊,他产生了『世界那么大,我想去看看』的念头,做出了退学的决定,然后一个人来到智利的Valparaiso小镇。那时候他尚不知道找一个什么样的工作来糊口,期间他曾熬夜做了一些不切实际的研究,如如何通过云进行通信。与后来苹果发布的iCloud似乎有那么点相似,也是没谁了。。

从那起,Ryan Dahl不知道是否因为生活的关系,他开始学习网站开发了
走上了码农的道路
走上了码农的道路
走上了码农的道路
那时候Ruby on Rails很火,他也不例外的学习了它。从那时候开始,Ryan Dahl的生活方式就是接项目,然后去客户的地方工作。
【在他眼中】,拿工资和上班其实就是去那里旅行

image.png

此后他去过很多地方,如阿根廷的布宜诺斯艾利斯、德国的科隆、奥地利的维也纳。

此后大家也都猜到了

2008年V8随着Chrome浏览器的出世,JavaScript脚本语言的执行效率得到质的提升,这给Ryan Dahl带来新的启示,他原本的研究工作与V8之间碰撞出火花,V8满足他关于高性能Web服务器的想象:

1. 没有历史包袱,没有同步I/O。不会出现一个同步I/O导致事件循环性能急剧降低的情况。
2. V8性能足够好,远远比Python、Ruby等其他脚本语言的引擎快。
3. JavaScript语言的闭包特性非常方便,比C中的回调函数好用。

2009年的2月,按新的想法他提交了项目的第一行代码,这个项目的名字最终被定名为“node”。
2009年5月,Ryan Dahl正式向外界宣布他做的这个项目。
2009年底,Ryan Dahl在柏林举行的JSConf EU会议上发表关于Node.js的演讲,之后Node.js逐渐流行于世。

Ryan Dahl于2010年加入Joyent(硅谷的创业公司),全职负责Node.js项目的开发。此时Node.js项目进入了它生命历程里的第二个阶段:从个人项目变成一个公司组织下的项目。

2.2 同父异母的斗争

可能大家偶尔会听到iojs/nodejs,究竟是什么❓其实他俩也就是同父异母的难兄难弟。

公司的宗旨是什么❓赚钱也好,为人民服务也罢,总之先看一下Joyent的历届负责人吧

1. Ryan Dahl;
2. Gatekeeper Isaac Z. Schlueter: 创建npm inc.公司时期,版本迭代开始放慢;
3. Gatekeeper Timothy J Fontaine: 取消了贡献者的CLA签证,让任何人可以贡献代码。Joyent对于项目的不作为和
其他层面对社区其他成员的干预,导致项目进展十分缓慢,用蜗牛的速度来形容一点也不为过。
4. Mikeal Rogers(request的作者):2014年成立“Node forword”组织。【io.js】的前身,希望创建一个开放的模式
进行协作,与管理层分歧。

最后一位Mikeal Rogers(request的作者)因为影响力大,有话语权,并且引导【io.js】的前身,所以你懂得
由于种种原因吧,从第二任领导者节奏开始放缓慢,靠这个改变世界呢,你们怎么可以拖后腿,不行🚫,矛盾越来越深,以至于2014年成立“Node forword”组织。正式开始分为两个组织,【本着改变世界的态度继续奋勇向前。】io.js的更新可谓是一发不可收拾,以周为单位。

image.png

毕竟一衣带水的关系使得最终双方各有妥协,最终握手达成一致继续为人类为程序员的梦想奋斗

image.png

这站图有点早了,但是后续是康庄大道,所以重点突出就够了。

image.png

第三部分 Nodejs的本质

说到本质,那网络上经常所说的Nodejs是单线程的、异步非阻塞的I/O、高并发....云云。如果仔细看,怎么觉得单线程高并发不是天生一对。其实【对 Node.js 的单线程一直有个误会。】
来,跟我默读三遍这句话。

Node.js 实际上是 Javascript 执行线程的【单线程】,真正的的 I/O 操作,底层 API 调用都是通过【多线程】执行的。

也就是说我们所操作的确确实实是【单线程】,然而内部也确实是【多线程】,否则怎么可能【高并发】。
对于【无法充分利用多核CPU】这个问题,其实可以开启多进程的,先不做展开,要不篇幅太长了。。。。

主要参考自淘宝前端团队

3.1 Nodejs结构

image.png

Node.js 的结构大致分为三个层次:

1. Node bindings:承上(js)启下(操作系统),实现在 node.cc
这一层是支撑 Node.js 运行的关键,由 C/C++ 实现。
2. V8:Google 推出的 Javascript VM,也是 Node.js 为什么使用的是 Javascript 的关键,
它【为 Javascript 提供了在非浏览器端运行的环境】,它的高效是 Node.js 之所以高效的原因之一。
3. Libuv:它为 Node.js 提供了【跨平台,线程池,事件池,异步 I/O 等】能力,是 Node.js 如此强大的关键。
4. C-ares:提供了异步处理 DNS 相关的能力。
5. http_parser、OpenSSL、zlib 等:提供包括 http 解析、SSL、数据压缩等其他的能力。

Libuv 是 Node.js 关键的一个组成部分,它为上层的 Node.js 提供了统一的 API 调用,使其不用考虑平台差距,隐藏了底层实现。

image.png

实际上,Node.js 虽然说是用的 Javascript,但只是在开发时使用 Javascript 的语法来编写程序。
真正的执行过程还是由 V8 将 Javascript 解释,然后由 C/C++ 来执行真正的系统调用,所以并不需要过分担心 Javascript 执行效率的问题。
可以看出,Node.js 并【不是一门语言,而是一个平台】,这点一定要分清楚。

3.2 异步I/O、非阻塞I/O

可以参看一下Linux IO模式及 select、poll、epoll详解,总结的很全面的。

image.png

通过上面的图片,可以发现non-blocking IO和asynchronous IO的区别还是很明显的。在non-blocking IO中,虽然进程大部分时间都不会被block,但是它仍然要求进程去主动的check,并且当数据准备完成以后,也需要进程主动的再次调用recvfrom来将数据拷贝到用户内存。而asynchronous IO则完全不同。它就像是用户进程将整个IO操作交给了他人(kernel)完成,然后他人做完后发信号通知。在此期间,用户进程不需要去检查IO操作的状态,也不需要主动的去拷贝数据。[signal driven IO并不常用]

最后,再举几个不是很恰当的例子来说明这四个IO Model:
有A,B,C,D四个人在钓鱼:

1. A用的是最老式的鱼竿,所以呢,得一直守着,等到鱼上钩了再拉杆;
2. B的鱼竿有个功能,能够显示是否有鱼上钩,所以呢,B就和旁边的MM聊天,隔会再看看有没有鱼上钩,有的话就迅速拉杆;
3. C用的鱼竿和B差不多,但他想了一个好办法,就是同时放好几根鱼竿,然后守在旁边,一旦有显示说鱼上钩了,它就将对应的鱼竿拉起来;
4. D是个有钱人,干脆雇了一个人帮他钓鱼,一旦那个人把鱼钓上来了,就给D发个短信。

了解了基本的概念之后,回归正题。
Libuv 本身就是异步和事件驱动的,所以,当我们将 I/O 操作的请求传达给 Libuv 之后,Libuv 开启线程来执行这次 I/O 调用,并在执行完成后,传回给 Javascript 进行后续处理。

有了以上内容的了解,言简意赅的一句话。总结并清楚的理解nodejs到底是什么。

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。

第四部分 给我一个选择nodejs的理由!

4.1 JavaScript助力

想了解JavaScript的势头,我们先看一下2016年GitHub统计的数据报告github语言排行

不想放大图

人口基数大就是红利,对吧!
【前端离不开JS】、【Mongodb也支持JS】、【后端nodejs、、、】梦想还是得有的,万一就这么一块写了呢

image.png

想想都™替程序猿、加班狗心疼。。。。

4.2 V8助力

Google 推出的 Javascript VM,也是 Node.js 为什么使用的是 Javascript 的关键,
【为 Javascript 提供了在非浏览器端运行的环境】,它的高效是 Node.js 之所以高效的原因之一。

image.png

4.3 npm助力

全球最大的开源库生态系统---npm。

我们不生产代买,只做代码的搬运工

image.png

这里不过多的操作,个人觉得没有概念学习时总是云里雾里的不知所踪。npm 是干什么的?(非教程)有兴趣的可以参考一下。

大致意思就是,假如之前你需要(jQuery、BootStrap...)等等包的时候,你需要去每个官网下载,然后配置到项目中,现在你只需要在package.json中配置对应的模块的名称版本号,然后npm install就好了.用法就这么简单。如下:

image.png

NPM Fix

4.3.1 npm 加深

(1)npm含义:

1. 一层含义是Node的开放式模块登记和管理系统,网址为npmjs.org;
2. 一层含义是Node默认的模块管理器,是一个命令行下的软件,用来安装和管理Node模块。

npm不需要单独安装。在安装Node的时候,会连带一起安装npm。

(2)功能

1. 允许用户从 npm 服务器下载别人编写的第三方包到本地使用。
2. 允许用户从 npm 服务器下载并安装别人编写的命令行程序到本地使用。
3. 允许用户将自己编写的包或命令行程序上传到 npm 服务器供别人使用。

(3)升级的效果
npm官网

image.png

npm3.x

2016年Facebook也推出了npm的替代品---yarm,有兴趣的可以了解下。

4.4 ebay选择Nodejs的理由

可以归纳为以下4点:

1. 动态语言:开发效率非常高,并有能力构建复杂系统,如ql.io。
2. 性能和I/O负载:Nodejs非常好的解决了IO密集的问题,通过异步IO来实现。
3. 连接的内存开销:每个Node.js进程可以支持超过12万活跃的连接,每个连接消耗大约2K的内存。
4. 操作性:实现了Nodejs对于内存堆栈的监控系统。

第五部分 Nodejs可以做啥?

在聊完nodejs的历程与本质之后,相信对nodejs已经有了个大致的清晰的概念。

任何事物都有其擅长行与局限性

你让马云去写代码,估计不如让他继续集众所长去change the world.
尺有所短,寸有所长,物有所不足,本着择其善者而从之的理念去汇总一下nodejs的优势与局限。

5.1 nodejs优势

1. 基于JavaScript语言
2. 基于最快的V8引擎
3. 异步非阻塞I/O
4. 全球最大的开源库生态系统

5.2 nodejs经常被提及的局限

如果我们去网上查找资料,不难发现以下劣势:

1. 可靠性低
2. 单进程,单线程,只支持单核CPU,不能充分的利用多核CPU服务器

但是,如果还没忘记Nodejs的本质的话,不难发现这些其实并不是劣势,甚至可以说这个说法说是不准确的,从原理上讲:

  1. 如果可靠性低,那么为何PayPal、沃尔玛、优步等等国际性大公司会采用nodejs?,其实这个劣势就不攻自破了。
  2. 无法充分利用多核CPU。这个问题其实可以使用 Node.js 自带的 cluster 模块【当然对于进程调度的开销我们先不谈】

既然以上的劣势是有针对性的,或是自相矛盾的,不论如何,我们从原理上看一下,它不适合哪些应用,然后我们在实践中避开就可以了。

V8【为 Javascript 提供了在非浏览器端运行的环境】,它的高效是 Node.js 之所以高效的原因之一,但也有相应的局限性

1. 计算密集型应用,让Javascript和C去拼计算性能,估计是不可能赢的。
2. 内存控制,让Javascript和Java比较复杂数据类型定义,也是很困难的。因为Javascript的面向对象是基于JSON的,而Java是直接使用内存结构。所以,通过JSON序列化和反序列的过程控制内存,Javascript就已经输了。
3. 大内存的应用,由于V8引擎有内存设计的限制,32位环境中最大堆是1G,64位环境中最大堆也不到2G,如果要一次读入10G数据,对于Nodejs来说也无法实现。
4. 静态服务器,虽然Nodejs的优势在IO密集集应用,但是和Nginx的处理静态资源还是有很大的差距。
5. 不需要异步的应用:比如系统管理,自行化脚本等,还是Python更顺手,Nodejs的异步调用可能会给编程带来一些麻烦。

比如我们常见的模板渲染、压缩、解压缩、加/解密等操作,都是 Node.js 的【软肋】,所以使用的时候要考虑到这方面。

5.3 适用的场景

这个文章已经总结的非常好了,建议大家可以参考一下--10个最佳Node.js企业应用案例:从Uber到LinkedIn

image.png

第六部分 学习路径

image.png

第七部分 总分总

image.png

参考
关于C10K、异步回调、协程、同步阻塞
Node.js软肋之CPU密集型任务
Node.js 探秘:初识单线程的 Node.js
Linux IO模式及 select、poll、epoll详解
IO - 同步,异步,阻塞,非阻塞 (亡羊补牢篇)
10个最佳Node.js企业应用案例:从Uber到LinkedIn

更多精彩内容请关注“IT实战联盟”哦~~~


IT实战联盟.jpg
上一篇 下一篇

猜你喜欢

热点阅读