设为首页 收藏本站
查看: 1018|回复: 0

[经验分享] 【转】学习NodeJS第二天:漫谈NodeJS

[复制链接]

尚未签到

发表于 2017-2-21 08:06:32 | 显示全部楼层 |阅读模式
  新型的服务端正在进入我们的视野,让我们投入了关注的目光,例如近来的 NodeJS
算比较抢眼的一员。

之所以创造NodeJS
,引用原作者 Ryan 之
语,目标是为了可以更轻松地编写具有可伸缩性的网络程序。咋一想,这样的目标作为网络开发人员们何曾不想拥有。——于是看看Nodejs
是怎么实现的。首先由浅入深说下简单的概念:无论是复杂的业务逻辑,还是简单的“HelloWorld”
也罢,客户端发送链接过来,Web
服务器肯定要一一全单照收,不会拒“链接”于千里之外。当中所说的性能指标即为我们日常会提到的——“并发(Concurrency

)”。Web
服务器是并发处理这些链接请求的。并发越高,服务器性能越好——到最终,大概是要解决著名 “C10K
问题”。在处理并发的这个技术问题上,NodeJS
表现出来的,就是高并发、低消耗的佼佼者。 DSC0000.gif

NodeJS
有一定性能优势,也引发了我们技术人员的浓厚兴趣。不免要问,NodeJS
是如何办到的?NodeJS

开源项目,如果不打算直接通过源码了解,我们还是可以利用网上一点资讯去了解的。笔者收集了关于 NodeJS
的几遍文章、博客,略有心得,将它们想表达 NodeJS
的特点、缺点、相关原理、前期分析、选型等等各方的问题“共冶一炉”,说出个NodeJS
初步分析的大概。

如果各位看官不太了解服务端的运作的话,我们稍微回顾一下请求 Request
这一环节的过程。现今多数的 Web
服务器中,有一条新的链接就会申请一条线程来负责处理至到这个Request
周期结束,接着执行其他流程。可以想象,成千上万个链接便有成千上万条线程(Thread-spawning
)。每条线程姑且以堆栈2MB
的消耗去计算,一条条线程它们的累加都是不小的数目。如何优化和改进本身就是一个大问题,此外,使用系统线程,必须考虑线程锁的问题,否则造成堵塞主进程又是一个令人操心的难题。NodeJS
则通过基于事件的异步模型绕开了基于线程模型的所带来的问题。NodeJS
使用 JavaScript
单线程(Single-threaded
)轮询事件,设计上比较简单,高并发时,不仅根本性的减少了线程创建和切换的开销(因而没有吓人的消耗),而且由于没有锁,也不会造成进程阻塞。每当有链接发起到服务端之后,NodeJS
会分发 epoll
kqueue
dev/poll

select
指令通知操作系统,有新链接到达,应执行指定的回调函数(Callback
)。每个链接从成本上说只消耗一个堆(heapallocation
)。



单线程的 Nodejs



NodeJS
使用单线程就足以提供高速的并发能力?是的,实际上著名nginx
也是基于单线程的。然而拜C++

所赐,NodeJS
之于 V8 运行时却拥有多线程的运行环境。怎么理解这点呢?就是一门脚本语言去代替相对复杂的网络编程。NodeJS
带有 JS

的名称,即以 JS
为卖点,由此可见其简单性浮出水面了——这确实也就是开发 NodeJS
的初衷之一,众所周知,JS 是轻盈的,
用来替
C++ 来

跟开发人员打交道——再美好不过,但必须强调,JS
终究是编写中间件的脚本语言,底层发挥作用的依然是功不可没的 C++
。为了实现这些设计目标,NodeJS
使用了Google
V8

并打包了其中的一些库:




  • libev
    实现了时间循环并封装了底层使用的具体的技术(如select,epoll
    等)。



  • 作者自己写的
    http-parser

    等协议和其他等等。


  其中 libev
正是实现多线程
NodeJS

的基础(edit on 2010-9-12:Are you sure to say so???有什么证据??)。JavaScript
仍旧发挥脚本语言的本色,一方面将 C++

的复杂性屏蔽,一方面向程序员呈现优雅的 API
NodeJS
  在适合一些较轻松的场合,例如一些分离器 Dispatcher
Request
BeansTalk
AMQP
消息应该没有问题。但依据国外一些博客文章分析就是,实际生产中可能会意外频频,发生一个错误就会挂起 NodeJS
,所以单线程不太可靠或许是NodeJS
一个先天的缺点。另外,编写 NodeJS
的扩展仍需要出来高深的C++
,恐怕须完善好 C
JS
之间的接口层,编写 NodeJS
扩展则才是我辈能力范围内的。写本文的时候,NodeJS
属新生事物,无须讳言,笔者没有太多的一线经验。话说回来,究竟实际上有多少的情景允许我们一边计算,一边做其他的事情而稳定无虞的呢?希望可以有待更多的观察。

上述的几点,的确提到了“基于线程模型”v.s“
基于事件模型”之争,目的就在于,除了明晰分辨它们的利弊之外,还不能不回答这样一个问题:既然“基于线程模型”消耗得那么厉害,那么为什么现在这么多的 Apaches
IIS
都运行得好好的?

基于事件的 Web
服务器相对是比较新的概念,可以做到比较好的性能,因而受到推崇一点不意外,像
NodeJS
那样的,——而传统的基于线程的模型服务器成熟程度高,况且仍不断地发展,例如 Apache
PHP
会派生出很多的
OS

线程来解决并发的问题,若一个请求挂起了其所在的线程,可以保证其他的线程也不会受到影响,不会冻结整个服务器进程,显得也比较合理。必须指出的是,像对于如何处理并发来选择“基于线程模型”v.s“
基于事件模型”这样的讨论,业界一直存在,并不是说基于事件模型的一定优秀无敌,尚有许多一一斟酌讨论的地方,具体如何就不一一展开了。

那么,NodeJS
的优势到底在哪?



应对长链接的压力


例如某网站 pv
非常可观,与用户互动频繁,那么它的线路总是处于高峰,自然它的网络进进出出肯定非常频繁,势必要求后台要赶快处理好前一个请求,以便接着有时间来处理一个请求,越快越好、越高效。好在,我们的请求大小都不是很大,通常几十字节(如http://domain:80
,一个
GET

操作,cookies
不大的话),控制线程在一个很小的单位,如此往返一个来回很快搞掂。那当然属于I/O
最简单的情况了,稍为复杂的一些就是
POST
  表单、文件上传等的任务。但好在不是每个链接皆如此,服务器还可以吃得消久一点的链接。可是,这时候,来问题了——

话说 Web2.0
时兴的元素,WebIM
WebGAME
Web
协作……无一不需求长链接为其服务的。长链接,或长轮询,是企图突破现有
HTTPv1.1

链接模型,把无态(Stateless
)的点对点链接变为人们理想的有态(Stateful
),也就是 Request/Response
互不分离,总是在线有沟通着。实际情形
HTTP

并没有提供这种的 API
或者说服务。当前我们大抵采用折衷的方法:打开一 HTML
页面立刻发送服务端的 AJAX
请求,就算是没有内容的请求都好,没有关系,服务器就千万别像普通
AJAX

那样接收请求,处理流程后就返回 Repsonse
,不要立刻返回内容而是等待,换言之,就是保持链接。只是在有消息发出的时候才返回 Response
然后浏览器渲染
Response
内容。例如,有好友发悄悄话给你,通过服务器发送到你浏览器上显示,然后立刻发起新的请求,让彼此之间的链接一直保持下去。

介绍前面的这么多,无非想说明,客户端与服务端一旦链接后,除非用户关闭浏览器,否则是不会断开keep
-alive
链接的。这样,对于同时维系着数十条或者数百条(聊天室)的
connection

的服务器,一直非空闲,还要顾上各方面资源(CPUusage
consumingmemory……
),显然不是一件容易事情,甚至如项目“开心网”那样成千上万笔
connection
场景就是对服务端极大的考验,如果占用的线程不能得到迅速释放,将会给服务器带来灾难性的后果!

于是一些 WebSerever
开始认真考虑这点,在新版中提供适应长链接的场景,例如 Java 世界的 Jetty
就很早的时候提供了一个J2EE
容器的解决方案,与
Comet

的通讯协议对接上。每个Server
的架构不一,然而如何改进和改进目标都有参考意义,但改进已是必然了,就要重新考虑 WebI/O
,提供足够快而稳定性能适应长链接的场景。明显,不得不重新考虑服务端的设计了,然而,背后要考虑的事情就多了。总之,可以想象任务艰巨性,不仅要考虑前方
I/O

高并发,低响应时间的请求,还要考虑整套的服务供应者怎么去资源调控,具体如负载平衡(LoadBalancing
)、动态 DNS
切换、DB
的集群、多个文件镜像的问题,往往配合起来就有许多不可预料的问题发生。一个环节有问题真个系统的堵塞了。这一启承转合要处理好。

DSC0001.jpg

不是有 WebSocket
标准吗?HTML5
的世界尽管在移动平台上很热闹,普通浏览器升级却觉得是另一回事。如果现在一下子都是支持
WebSocket

的浏览器,那不用说准是皆大欢喜了,但事实和将来的预测表明 WebSocket
完全是另外一回事,咱和咱用户面对的仍旧那些僵硬不化的
IE6……
所以说在
WebSocket

不现实的今天,将善于“长链接”的 NodeJS
派上用场便有很充分的理由。

p.s
:……包括用flashsocket
组件那些
hack
的都不算。



发挥事件模型的威力


NodeJS
带来了一股清新之风,与其所使用 JS
乃密不可分的。这次,神奇的
JavaScript
又一次成为了胶水语言,为“基于事件驱动模型(Evnent-based
)”开发埋下重要的伏笔。事件本质上一个时空不一致的非线性模型,或所谓的“异步(Asynchronization
)”。事件发生的顺序按照外界对其发出的时刻而确定,有的在先,有的在后,有时也可以齐头并进,一起同时触发,——结束时也可以快的快、慢的慢。(呵呵,本人有些无聊,既然说到这儿,就突然想起小学课本,华罗庚那篇的《统筹方法
》“……想泡壶茶喝。当时的情况是:开水没有。开水壶要洗,茶壶茶杯要洗;火已升了,茶叶也有了。怎么办?……”,实有异曲同工之妙!)。具体说,就是在一方面处理诸如数据库查询/
存储、磁盘读写、网络延时那一类费时的任务,一方面处理内存中高速的运作,来作一个合理地平衡调度。当然,回归这一点的要求与多线性模型的
I/O

要求是无异的。总之不是直接的某个函数 method()
去执行(那是同步的方式,Node.js
也支持),而是写回调 callback
;如果换了是同步方式,就必须等待上一个任务结束,才能开始下一个任务。本来可以齐头并进的机会却白白浪费掉了。换言之,大多数操作往往是I/O

的等待,不过 NodeJS
底层对于 JavaScript
该层面来说,由后台线程调用 JavaScript
函数,因此无碍
JS

代码本身执行,实现异步的操作,即“非阻塞”。例如下面摘自文档的一个例子:


    var   posix = require("posix")  ,sys = require("sys");      
var promise = posix.unlink("/tmp/hello");
promise.addCallback(function () {        
sys.puts("successfully deleted /tmp/hello");   
});  

 
如果删除文件成功,触发 success
事件执行addCallback()
所定义的回调函数;即是删除文件失败,产生
wait

的信号,直至 timeout
的时限,也不会阻塞其他 JS
代码的执行。在Node.js
API
中,到处使用事件的概念,包括许多方法都设有“同步”和“异步”的两种方式供选择,故所以我们不用担心写的代码会阻塞 Node.js
I/O


个人认为,从感觉而言,两者之间还有一点的差异可能是,多线性模型不像编写事件那么自然。定义事件起来隐约会有一种写“DSL”
的感觉,尤其在JS
这个
Function First
Class的脚本帮助下。另外可以参考一下前一篇《node.js引言 》的博文
,此处不再复述。

题外话:貌似
AJAXAIR in Js

呈现了也是一种异步调用方式(记得
SQLquery

时语法相似)。

DSC0002.jpg

事件循环的console模拟图

实际上,NodeJS
不是第一家标榜事件的WebServer
,早在
NodeJs
之前,在各种语言中都有事件的实现,不能不提的就是 nginx
。不过使用 JavaScript
的还属于头一遭吧?过去几年可以说是
JS

引擎发展的高峰期,就连最保守的微软也要 IE9

把落后的 JS
解释速度争回来,亲爱的服务端方面却又怎么按耐的住呢?自然,革新速度后,JSVM
引入到 Serverside
的工作更是一件顺理成章的事。

话说回来基于事件理念的 Server
NodeJS 的 idea
最初启发自 Ruby

EventMachine

Python
Twisted
,将包括各种
I/O
操作定义在回调函数中,通过事件不断轮询任务列表来触发那些 Callback
,——并且
NodeJS
有创新的地方,就是提出新的思路来呈现事件机制。从原理上讲,NodeJS
不仅仅是一个库,而是尝试利用语言机制来构建的事件模型。EventMachine

Twisted

却不是这样,它们都是在代码开始和结束的时候插入回调函数来完成一个阻塞的调用,然后这个过程的启用,就用:


EventMachine::run()  

 
NodeJS
没有这种代码顺序的限制,可以在定义代码之后再插入新的代码,继续参与事件。同时NodeJS
也不会
TwistedPython

那样提供“延时线程(deferto thread
)”,实际是堵塞代码的“陷阱”。

尽管我们这里说的事件模型好像比较简单,但是许多的基础设施对异步操作的支持的不足的,尤其普通用户根本不会自己去创建业务事件。相关内容在介绍 NodeJS
Slide
有介绍(搜索jsconf.pdf
),说明为什么
NodeJS

出现之前没有类似 NodeJS
的“物体”出现,同时也说明设计
NodeJS
要克服的难关。



结语


最后一点,谈谈
NodeJS

为什么选择 GoogleV8

JS
引擎而不是另一个著名的
SpiderMonkey

引擎。抛开速度等的硬性指标不表,依然可能是 SpiderMonkey
源码仍比较复杂的缘故,不好把玩,既然这样,人们于是自然就青睐 V8 了


本文介绍了一位 JS
爱好者对 NodeJS
以及后台初步感性的了解,没有深刻的认识,竟也成文,看官们可作一定取舍(trade-off
),将就来读,或请积极献言,一同讨论。

参考:

WernerSchuster
http://www.infoq.com/news/2009/11/nodejs-evented-io



LouisSimoneau
Node.js is theNew Black


UDP& Dgram UNIX daemon Socket supporthttp://groups.google.com/group/nodejs/browse_thread/thread/665422a1dc28d874



PaulQuerna, Drinking the Node.js Kool-Aid

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-344946-1-1.html 上篇帖子: nodejs安装脚本 下篇帖子: ContsOs安装nodejs
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表