1、Node.js是什么
1.1、Node.js是让Javascript运行在服务器端的开发平台
NodeJS并不是独立的语言,也不是Javascript框架,也不是浏览器端库。
NodeJS是一个让Javascript运行在务器端的开发平台,让Javascript运行在浏览器之外的平台,实现了很多的模块:文件系统,模块,包,操作系统API,网络通信等CoreJavascript中没有或者不完善的功能。
1.2、异步式I/O与事件驱动
这也是NodeJS最大的特点
传统的架构:多线程,为每个业务逻辑提供一个系统线程,通过系统线程切换来弥补同步时I/O调用时的时间开销。
NodeJS使用的是单线程模型,对于所有I/O都采用异步式请求的方式,避免了上下文切换。在执行过程中维护着一个事件队列,程序在执行时进入事件循环等待下一个事件到来,每个异步式I/O请求完成后会被推送到事件队列,等待程序进入进行处理。
代码示例:
res = db.query(‘select * from some_table’);
res.output();
db.query(‘select * from some_table’, function(res){
res.output();
});
NodeJS进程在同一时刻只会处理一个事件,完成后立即进入事件循环检查并处理后面的事件。CPU和内存在同一时间集中处理一件事,同时尽可能让耗时的I/O操作并行执行。只会在事件队列中添加请求等待操作系统的回应,因而不会有任何多线程开销,很大程度上可以提高Web应用的健壮性,防止恶意攻击。
1.3、统一在Javascript浏览器之外的实现, CommonJS
CommonJS试图定义一套普通应用程序使用的API,从而填补Javascript标准库过于简单的不足。CommonJS的终极目标是制定一个像C标准库一样的规范,使得基于CommonJS API的应用程序可以在不同的环境下运行,就像用C编写的应用程序可以使用不同的编译器和运行时函数库一样。
CommonJS规范: 模块,包,系统,二进制,控制台,编码,文件系统,套接字,单元测试等。
NodeJS是CommonJS规范最热门的一个实现。
1.4、CommonJS的各种实现
ringoJS: RingoJS 是一个用 Java 编写的 JavaScript 运行环境,基于 Mozilla 的 Rhino 的 JavaScript 引擎,可用来开发Web应用程序。
persevere:
mongoDB:基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。MongoDB[2]是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。
couchDB: 是一个开源的面向文档的数据库管理系统,可以通过 RESTful JavaScript Object Notation (JSON) API 访问。
2、Node.js的优势
2.1、不需要放在 Nginx / Apache 后,Node.js本身就内置了一个HTTP模块
NodeJS内建了一个HTTP服务器支持,可以轻而易举的实现一个网站和服务器的组合,不像PHP、Perl那样,在使用PHP的时候,必须先搭建一个Apache之类的HTTP服务器,然后通过HTTP服务器的模块加载CGI调用,才能将PHP脚本的执行结果呈现给用户。
加载http模块之后,即可创建一个http服务器
var http = require(‘http’);
http.createServer(function(req, res) {
res.writeHead(200, {‘Content-Type’: ‘text/html’});
res.write(‘
Node.js
’);res.end(‘
Hello World
’);}).listen(8080);
2.2、Node.js 可以更精细的控制 Request 和 Response 的时间和内容
http.request(options, callback)
Options:
host: A domain name or IP address of the server to issue the request to. Defaults to ‘localhost’.
hostname: To support url.parse() hostname is preferred over host
port: Port of remote server. Defaults to 80.
localAddress: Local interface to bind for network connections.
socketPath: Unix Domain Socket (use one of host:port or socketPath)
method: A string specifying the HTTP request method. Defaults to ‘GET’.
path: Request path. Defaults to ‘/’. Should include query string if any. E.G. ‘/index.html?page=12’
headers: An object containing request headers.
auth: Basic authentication i.e. ‘user:password’ to compute an Authorization header.
agent: Controls Agent behavior. When an Agent is used request will default to Connection: keep-alive.
Class: http.ServerResponse
Event: ‘close’
response.writeContinue()
response.writeHead(statusCode, [reasonPhrase], [headers])
response.setTimeout(msecs, callback)
response.statusCode response.setHeader(name, value)
response.headersSent response.sendDate response.getHeader(name)
response.removeHeader(name)
response.write(chunk, [encoding])
response.addTrailers(headers)
response.end([data], [encoding])
2.3、能支持数万个并发连接
Node.js 用异步式 I/O 和事件驱动代替多线程,带来了可观的性能提升。Node.js 除了使用 V8 作为JavaScript引擎以外,还使用了高效的 libev 和 libeio 库支持事件驱动和异步式 I/O。
2.4、采用事件驱动、异步编程,为网络服务而设计
异步编程的设计,重要的优势在于,充分利用了系统资源,执行代码无须阻塞等待某种操作完成,有限的资源可以用于其他的任务。此类设计非常适合于后端的网络服务编程,Node.js的目标也在于此。
在服务器开发中,并发的请求处理是个大问题,阻塞式的函数会导致资源浪费和时间延迟。通过事件注册、异步函数,开发人员可以提高资源的利用率,性能也会改善。
3、Node.js的缺点
3.1、可靠性低
不支持故障恢复
当程序有错误发生时,整个进程就会结束,需要重新在终端中启动服务器。这一点在开发中无可厚非,但在产品环境下就是严重的问题了,因为一旦用户访问时触发了程序中某个隐含的bug,整个服务器就崩溃了,将无法继续为所有用户提供服务。在部署Node.js 应用的时候一定要考虑到故障恢复,提高系统的可靠性。 (后面讲多线程多进程支持的时候看看怎么解决的)
3.2、单进程,单线程,默认支持单核CPU(支持多进程的方法)
NodeJS中的相关模块:
cluster:生成与当前进程相同的子进程,并且允许父进程和子进程之间共享端口。cluster 允许跨进程端口复用。
Node.js 的另一个核心模块child_process 也提供了相似的进程生成功能。
cluster.js 的功能是创建与CPU 核心个数相同的服务器进程,以确保充分利用多核CPU 的资源。主进程生成若干个工作进程,并监听工作进程结束事件,当工作进程结束时,重新启动一个工作进程。分支进程产生时会自顶向下重新执行当前程序,并通过分支判断进入工作进程分支,在其中读取模块并启动服务器。
使用cluster模块
var cluster = require(‘cluster’);
var os = require(‘os’);
// 获取CPU的数量
var numCPUs = os.cpus().length;
var workers = {};
if (cluster.isMaster) {
// 主进程分支
cluster.on(‘death’, function (worker) {
// 当一个进程结束时,重启工作进程
delete workers[worker.pid];
worker = cluster.fork();
workers[worker.pid] = worker;
});
// 初始化开启与CPU数量相同的工作进程
for (var i = 0; i < numCPUs; i++) {
var worker = cluster.fork();
workers[worker.pid] = worker;
}
} else {
// 工作进程分支,启动服务器
var app = require(‘./app’);
app.listen(3000);
}
// 当主进程被终止时,关闭所有工作进程
process.on(‘SIGTERM’, function () {
for (var pid in workers) {
process.kill(pid);
}
process.exit(0);
});
3.3、太新了,API还在成熟过程中
var settings = require(‘./settings’);
var MongoStore = require(‘connect-mongo’);
var settring = require(‘./settings’);
var MongoStore = require(‘connect-mongo’)(express);
因为异步的原因, 一些完整的逻辑不可避免的会被分割成很多小块, 放在不同的回调函数里去执行, 一旦项目巨大的话, 这种开发方式面临的风险不是一点点。不符合开发者的常规线性思路,往往需要把一个完整的逻辑拆分为一个个事件,增加了开发和调试难度。
// 传统代码
var user = db.user.get(‘name’);
var article = db.article.get(user.id);
var comment = db.comments.get(article.id);
// 异步回调
db.user.get(‘name’, function(err, user){
if(err) trow err;
db.article.get(user.id, function(err, article){
if(err) throw err;
db.comments.get(article.id, function(){
if(err) throw err;
// doSomethingWithResults();
})
});
});
解决方法:针对这个问题,Node.js第三方模块提出了很多解决方案,例如异步库 async。
4、NodeJS现阶段适合做什么
4.1、node适合io操作多,cpu操作少的场合
阻塞模式下,一个线程只能处理一项任务,要想提高吞吐量必须通过多线程。
而非阻塞模式下,一个线程永远在执行计算操作,这个线程所使用的 CPU 核心利用率永远是 100%,I/O 以事件的方式通知。在非阻塞模式下,线程不会被 I/O 阻塞,永远在利用 CPU。
多线程带来的好处仅仅是在多核 CPU 的情况下利用更多的核,而Node.js的单线程也能带来同样的好处。这就是为什么 Node.js 使用了单线程、非阻塞的事件编程模式。
4.2、数据简单,但是数据访问频繁的场合
5、NodeJS现阶段不适合做什么
5.1、高CPU消耗的app
最显而易见的用例是那种CPU使用率高同时I/O操作小的。所以如果你打算写一个视频编码软件,人工智能软件或者类似的CPU使用率高的软件,请不要用node.js。要是你肯稍微变通一下,用C或C++效果会更好。
但是,node.js允许你很轻松的写C++扩展,所以你可以把它作为一个你核心算法的脚本引擎。
NoSQL + Node.js——如果仅仅是为了追求时髦,且自己对这两门技术还未深入理解的情况下,不要冒险将业务系统搭建在这两个漂亮的名词上,建议使用MySQL之类的传统数据库
6、NodeJS比较热门的框架
6.1、UnitTest
· Expresso https://github.com/visionmedia/expresso
· Nodeunit https://github.com/caolan/nodeunit
Nodeunit:
npm install nodeunit
exports.testSomething = function(test){
// 指定一个测试内期望被执行的断言数量,确保你的回调和断言被执行到了。
test.expect(1);
// 判断是否为true
test.ok(1==1, ‘this assertion should pass’);
// 结束当前的测试函数并继续执行下一个
test.done();
};
exports.testSomethingElse = function(test){
test.equal(1, 3, ‘this assertion should fail’);
test.done();
};
express
它是目前最稳定、使用最广泛,而且 Node.js 官方推荐的唯一一个 Web 开发框架。Express ( http://expressjs.com/ ) 除了为 http 模块提供了更高层的接口外,还实现了许多功能,其中包括:q 路由控制;q 模板解析支持;q 动态视图;q 用户会话;q CSRF 保护;q 静态文件服务;q 错误控制器;q 访问日志;q 缓存;q 插件支持。
它只是一个轻量级的 Web 框架,多数功能只是对 HTTP 协议中常用操作的封装,更多的功能需要插件或者整合其他模块来完成。
Pomelo
pomelo是基于node.js的高性能,分布式游戏服务器框架。它包括基础的开发框架和相关的扩展组件(库和工具包),可以帮助你省去游戏开发枯燥中的重复劳动和底层逻辑的开发。 pomelo不但适用于游戏服务器开发, 也可用于开发高实时web应用,它的分布式架构可以使pomelo比普通的实时web框架扩展性更好。
rrestjs
rrestjs是在expressjs代码的基础上开发的node.js框架(这样可以减少很多bug,同时要感谢expressjs作者 visionmedia无私的奉献),不过整个框架结构已经完全改变了,属性以及方法定义也是全新的,可以说是一个全新的node.js开发框架(不仅局限于web页面的输出)。rrestjs命名源自:ROA-Restful,面向资源和restful是rrestjs的宗旨,和expressjs不同的是expressjs是利用路由机制的,而rrestjs则完全根据用户请求的uri去找寻控制器。
Meteor
如果简单定义“现代网站”是一个实时交互、超高性能、具备非凡体验的网站,那么 Meteor就是一个可为开发者以简单高效而且充满乐趣的方式进行现代网站开发的平台,以往开发周期需要几周到几个月的项目,现在可能只需要几个小时或者一个周末的时间就可以完成。Meteor构建的应用体验,会让人觉得浏览器的刷新按钮和地址栏是多余的。
7、基于NodeJS实现的案例
小米公司的抢购服务程序
搜狐小纸条后端采用NodeJS来处理 消息推送
NodeJS在朋友网的实践
统计用户在线时长 webim 服务器端推送其他消息