在汽车世界里,对于指定排量和发动机的车辆想要进一步压榨发动机性能,比较直接的办法就是加装涡轮增压套件,增加发动机进气量从而提升发动机的输出功率。 expressjs作为nodejs中比较热门的http框架被广大用户接受和使用,其性能也一直很受大家关注,我最近开发了两个模块 iroute 和 ifile 模块,可以用来给expreesjs加装涡轮增压器,提升expressjs框架的整体性能。
iroute模块具有简单路由功能 irotue模块项目地址: https://github.com/DoubleSpout/iroute 介绍地址: http://cnodejs.org/topic/51ae2043555d34c678a95c95 安装方法:
npm install iroute
ifile模块主要功能是对静态文件的输出 ifile模块项目地址: https://github.com/DoubleSpout/ifile 介绍地址: http://cnodejs.org/topic/51c3289573c638f370492f2e 安装方法:
npm install ifile
iroute和ifile模块都具有简单的api,高性能和跨平台特点,都在win8,linux,mac上测试通过,可以说是适合各种工况,欢迎大家下载试用,或者有什么功能特点我没考虑周全的更可以留言给我,不胜感激啊。
最后附上测试结果:
说明:注册get方式的1000个路由,直接get请求第1001个url,静态文件输出为同一个test.js,大小为6kb。
纯exppress
express only(1000 routes)
ab -c 100 -n 20000 http://192.168.28.5:8127/test/
Requests per second: 1271.83 [#/sec] (mean)
ab -c 500 -n 20000 http://192.168.28.5:8127/test/
Requests per second: 1237.43 [#/sec] (mean)
ab -c 800 -n 20000 http://192.168.28.5:8127/test/
Requests per second: 1191.17 [#/sec] (mean)
express only (static)
ab -c 100 -n 20000 http://192.168.28.5:8127/js/test.js
Requests per second: 918.91 [#/sec] (mean)
ab -c 500 -n 20000 http://192.168.28.5:8127/js/test.js
Requests per second: 806.83 [#/sec] (mean)
ab -c 800 -n 20000 http://192.168.28.5:8127/js/test.js
Requests per second: 701.42 [#/sec] (mean)
ab -c 500 -n 20000 -H "Accept-Encoding: gzip" http://192.168.28.5:8127/js/test.js
Requests per second: 596.43 [#/sec] (mean)
express+ifile+iroute
express+ifile+iroute (1000 routes)
ab -c 100 -n 20000 http://192.168.28.5:8128/test/
Requests per second: 1886.01 [#/sec] (mean)
ab -c 500 -n 20000 http://192.168.28.5:8128/test/
Requests per second: 1773.27 [#/sec] (mean)
ab -c 800 -n 20000 http://192.168.28.5:8128/test/
Requests per second: 1829.89 [#/sec] (mean)
express+ifile+iroute (static)
ab -c 100 -n 20000 http://192.168.28.5:8128/js/test.js
Requests per second: 1544.94 [#/sec] (mean)
ab -c 500 -n 20000 http://192.168.28.5:8128/js/test.js
Requests per second: 1655.26 [#/sec] (mean)
ab -c 800 -n 20000 http://192.168.28.5:8128/js/test.js
Requests per second: 1438.74 [#/sec] (mean)
ab -c 500 -n 20000 -H "Accept-Encoding: gzip" http://192.168.28.5:8128/js/test.js
Requests per second: 1591.59 [#/sec] (mean)
路由方面性能提升大约50%,在静态文件输出方面性能提升超过100%,真的是给expressjs框架增加了一个强有力的涡轮增压器了。
最后附上测试代码:
expressjs
var express = require('express');
var connect = require('connect')
var app = express();
app.use(connect.compress());
app.use('/js', express.static(__dirname+'/js'));
var len = 1000;
for(var i=0;i<len;i++){
app.get('/user/'+i+'/info/', function(req, res){
res.send('hello world2');
});
}
app.get('/test/', function(req, res){
res.send('test');
});
app.listen(8127);
expressjs+ifile+iroute
var express = require('express');
var app = express();
var iroute = require("iroute");
var ifile = require("ifile");
var array = [];
for(var i=0;i<1000;i++){
array.push(["get:/user/"+i+"/info/",function(req,res){res.end('hello world')}])
}
array.push(["get:/test/",function(req,res){res.end('test')}])
app.use(ifile.connect([["/js",__dirname]]));
app.use(iroute.connect(array))
app.listen(8128);
iroute与express的测试对比其实是不公平,前者的路由匹配只是简单的字符串对比(strncmp),后者则是正则式匹配。express以损失部分性能为代价,换来高度自由化的路由匹配和参数转换。如果express同样做字符串对比的简单路由匹配,可预计两者的性能是差不多的。
ifile建议再多做个流量测试。express在流量10M~100M下表现良好,至于ifile,呃,要求node v0.10+,我的vps装不了。居然不支持0.8这个超级稳定版本…0.10因为引入新的stream api,bug满天飞。说白了就是拿公众做测试肉鸡的版本,坐等0.12。
哈哈,又是你这位犀利哥,我比较喜欢你的评论,一针见血
iroute和express的路由机制不同,只要达到相同的目的,我想就算实现方式不同还是有一定可比性的,同样iroute也有请求method判断,参数是否存在的判断,多个middle ware过滤功能,只是express多了一个将参数的数值放在了路由里去判断了,但是为了这个功能损失的性能是不是有点得不偿失。
你说的流量测试是指带宽测试吧,测试在10Mbps和100Mbps下的表现吧。ifile其实目前有一个比较大的问题就是对于大size文件的响应,ifile会将整个文件全部读入内存然后再响应,如果文件过大,可能会造成内存crash,所以下个版本大文件还是要走nodejs的pipe,毕竟大文件的响应性能主要不是靠i/o的速度了,是靠带宽了。
至于0.8版本的node我想我们还是应该向前看,其实程序本身是应该支持0.8的,只是我在package.json中的支持写上了0.10.x,毕竟0.10版本也是官方推出的stable版本,0.8版本早晚成为历史的,而且在api上两者还是有变化的,想要全部兼容还得费点力。
哈哈,我就喜欢泼冷水的,听其他声音 1、nodejs缓存不理想是你打错字了吧,你是说静态文件响应不理想吧,静态文件建议公司生产环境还是用nginx或者cdn上去,但是个人网站什么的可能是nodejs空间,没有条件安装nginx的话还是只能使用nodejs来处理静态文件
2、反向代理主要工作是负载均衡,但是随之而带来的性能损耗也要计算在里面,反向代理应该使用在更适合的地方,单服务器我觉得没必要
@leizongmin hoho,加了个接口提交上去了,iroute简单多了
var express = require('express');
var app = express();
var iroute = require("iroute");
var route_array = [
["get:/hello/world",function(req,res){res.end('hello world')}],
]
app.use(iroute.connect(route_array));
app.listen(3000);
@snoopy 现在做的一个网站,生产环境下,启动应用时自动将资源文件发布到七牛云存储上,同时会自动修改模板中的资源文件路径。 Node.js只作为应用服务器,不提供资源文件服务。 本地开发环境,为了方便,则静态文件服务也有Node.js提供。
@snoopy nodejs缓存是语言层次的。不过你提到的静态缓存。反向代理抛开seo不谈。我觉得nginx的也是不错的选择。个人模块,我觉得作为市场开发模式的典型应用的确是一种十分可取的开发模式。但是对于大型项目,部署线上假如模块测试不完整很难快速定位错误和解决。不过我倒是很喜欢你写的东西。假如能够利用http协议将数据缓存在浏览器是种不错选择。第二。现在大部分利用ejs等模版插件。这部分需要每次运行时候编译,可以缓存吗?第三。假如缓存的是css跟图片.js。或许部署上有更好的选择。
@leizongmin 再看看代码,简单很多了,哈哈,封装好了api,大文件走pipe了
var express = require('express');
var app = express();
var iroute = require("iroute");
var ifile = require("ifile");
var array = [];
for(var i=0;i<1000;i++){
array.push(["get:/user/"+i+"/info/",function(req,res){res.end('hello world')}])
}
array.push(["get:/test/",function(req,res){res.end('test')}])
app.use(ifile.connect([["/js",__dirname]]));
app.use(iroute.connect(array))
app.listen(8128);
再看看代码,简单很多了,哈哈,封装好了api,大文件走pipe了
var express = require('express');
var app = express();
var iroute = require("iroute");
var ifile = require("ifile");
var array = [];
for(var i=0;i<1000;i++){
array.push(["get:/user/"+i+"/info/",function(req,res){res.end('hello world')}])
}
array.push(["get:/test/",function(req,res){res.end('test')}])
app.use(ifile.connect([["/js",__dirname]]));
app.use(iroute.connect(array))
app.listen(8128);
@snoopy 简单是简单了,但是我感觉现在的路由机制配置起来还是太繁琐了,类似java中struts的默认路由进制就比较好,比如说我一般url的组成形式是这样的http://host/controlname/functionName,这样的话就应该可以自动定位到控制器,控制器的方法,就不需要些这么繁琐的路由规则了,上只是个人想法。
@dengqiao 这种方式不如路由表来的直观,而且你想在某几个action中加入中间过滤middleware也还是要写判断,是一种方式,各人各喜欢了,最早我就用过try catch方式直接require模块执行里面的方法,后来和大牛们聊了会还是发现这种路由清晰,更易项目维护和交接
@dengqiao 这种方式如果你想要对其中一些aciton做middleware过滤就比较麻烦了,还是得再入口处做url匹配,利用app.all注册的路由匹配归根到底还是利用js的正则判断。iroute路由是基于char*的strncmp,所以在执行效率方面要比js的正则快一些。 不过路由这东西各人各喜欢了,不必强求了
@snoopy 那你最开始特指什么nodejs 缓存。其实我一直觉得Nodejs 做涉及文件处理的东西是个很蛋疼的事情。http 协议缓存不就是浏览器缓存吗。不知道你用这个做过什么东西测试一下正确性吗?