新型的服务端正在进入我们的视野,让我们投入了关注的目光,例如近来的 NodeJS
算比较抢眼的一员。
之所以创造NodeJS
,引用原作者 Ryan 之
语,目标是为了可以更轻松地编写具有可伸缩性的网络程序。咋一想,这样的目标作为网络开发人员们何曾不想拥有。——于是看看Nodejs
是怎么实现的。首先由浅入深说下简单的概念:无论是复杂的业务逻辑,还是简单的“HelloWorld”
也罢,客户端发送链接过来,Web
服务器肯定要一一全单照收,不会拒“链接”于千里之外。当中所说的性能指标即为我们日常会提到的——“并发(Concurrency
)”。Web
服务器是并发处理这些链接请求的。并发越高,服务器性能越好——到最终,大概是要解决著名 “C10K
问题”。在处理并发的这个技术问题上,NodeJS
表现出来的,就是高并发、低消耗的佼佼者。
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
正是实现多线程
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
的集群、多个文件镜像的问题,往往配合起来就有许多不可预料的问题发生。一个环节有问题真个系统的堵塞了。这一启承转合要处理好。
不是有 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
时语法相似)。
事件循环的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
分享到:
相关推荐
转到nodejs-restify目录: cd nodejs-restify 建立: docker build -t gmercer/nodejs-restify . 验证构建-检查是否存在新映像: docker images 要使用端口8080在后台(-d)中运行,请执行以下操作: doc
### 第二章:NodeJS核心模块 这一章节将介绍NodeJS的核心模块,这些模块是NodeJS内置的,无需额外安装即可使用。具体包括: #### 2.1 内置模块 NodeJS提供了多个内置模块来支持常见的功能需求,如文件操作、网络...
今天小编就为大家分享一篇关于nodejs npm错误Error:UNKNOWN:unknown error,mkdir 'D:Developnodejsnode_global'at Error,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看...
nodejs 学习笔记 nodejs 学习笔记 nodejs 学习笔记
nodejs基础学习视频nodejs基础学习视频nodejs基础学习视频nodejs基础学习视频
第二步:安装nodejs 第三步:npm安装 第四步:安装相关环境 第五步:安装CoffeeScript npm命令集合: 1、npm install moduleNames:安装Node模块 npm install express 默认会安装express的最新...
1. **事件驱动模型**:NodeJS的核心特性之一是其事件驱动非阻塞I/O模型,这使得NodeJS在处理大量并发连接时表现优秀。 2. **模块系统**:NodeJS使用CommonJS模块规范,通过`require`引入模块,`exports`或`module....
01-第一个 NodeJS8 快速上手小案例.mp4 02-利用NodeJS8 读取文件提作.mp4 03-NodeJS8异步读取服务器数据mp4 04-NodeJs8 完整读取视图文件mp4 05-利用Express第三方框架快速搭建NodeJS8 Web服务器.mp4 06-NodeJS8中的...
OpsWorks 中创建“自定义层” 将以下自定义配方添加到您的图层: 设置:nodejs-wrapper-opsowrks、nodejs-wrapper-opsworks::create-symlink 配置:opsworks_nodejs::configure 部署:nodejs,部署::nodejs 取消部署...
typescript使用nodejs实现简繁体转换,可以转换子文件夹, 运行方式:将文件复制到工程的files文件夹,运行node app.js "" s2t(简体转繁体)或node app.js "" t2s(繁体转简体)即可
nodejs安装及环境配置:Node.js 安装及环境配置指南; nodejs安装及环境配置:Node.js 安装及环境配置指南; nodejs安装及环境配置:Node.js 安装及环境配置指南; nodejs安装及环境配置:Node.js 安装及环境配置...
是我学习nodejs的Xmind路线,从入门到其它的数据库都已齐全。如果对node的学习没有头绪等,可以下载学习。
NodeJS 介绍与应用 Node.js 是一个基于 Chrome JavaScript 运行时建立的一个平台, Node.js 是一个事件驱动 I/O 服务端 JavaScript 环境(由 C++ 编写),基于 Google 的 V8 引擎,V8 引擎执行 JavaScript 的速度...
自我学习NodeJS技术 先决条件: JavaScript ES6 命令行 吉特 1.安装NodeJS 从下载安装程序。 要检查NodeJS的版本,请在cmd中运行Node -v 。 2.创建package.json 要创建package.json,请运行npm init并填充...
节点js NodeJS示例项目
学习流程第一部分:学习Nodejs核心API (Nodejs core API)第二部分:学习Nodejs编程基础 (Nodejs programming basics)第三部分:学习MySQL数据库第四部分:学习Express有什么想法和问题请在留言,或Gmail给我:....
NodeJS教程练习该文件夹包含一组文件夹,每个文件夹都包含一个基于某个教程的nodeJS应用程序。 在每个文件夹中都提供了README.md ,它详细说明了本教程的内容以及如何运行,调试和测试应用程序。 遵循每个文件夹的...
C和C ++是我的第一门编程语言,我从中学习了基础知识,并且我非常喜欢它们(尽管我很生锈) :grinning_squinting_face: )。 :globe_showing_Europe-Africa: 感兴趣的网站 :pushpin: 方法和准则质量保证规范(QAC)...
深入浅出Node.js(二):Node.js&NPM的安装与配置-http://www.infoq.com/cn/articles/nodejs-npm-install-config 2.NPM的命令: (1).unstall:npm unstall -g grunt-cli 3.环境变量: D:\Program Files\nodejs\; D:\...