精华 加装涡轮,提速expressjs
发布于 3 年前 作者 DoubleSpout 10495 次浏览

在汽车世界里,对于指定排量和发动机的车辆想要进一步压榨发动机性能,比较直接的办法就是加装涡轮增压套件,增加发动机进气量从而提升发动机的输出功率。 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);
55 回复

涡轮增压器 保养不便宜,还是自然吸气好了~

不申请添加到 express 官方wiki 当中?

看样子是快不少,但是后期维护麻烦,还不知道未知的bug~ express 性能够可以了。。

有时间看看原理,感兴趣!

有时间看一下原理。先收藏一下。

hoho~,我也喜欢自然吸气的线性加速,和高转速

等完善下功能再review几次代码再提交吧~谢谢啊

express性能是够用了,不过这2个模块就像涡轮,可以更进一步压榨它的性能

我发现社区没有表情系统 [good]

nice 期待啊,刚出的时候,看了数据就觉得很有前途,跟connect配合。

iroute与express的测试对比其实是不公平,前者的路由匹配只是简单的字符串对比(strncmp),后者则是正则式匹配。express以损失部分性能为代价,换来高度自由化的路由匹配和参数转换。如果express同样做字符串对比的简单路由匹配,可预计两者的性能是差不多的。

ifile建议再多做个流量测试。express在流量10M~100M下表现良好,至于ifile,呃,要求node v0.10+,我的vps装不了。居然不支持0.8这个超级稳定版本…0.10因为引入新的stream api,bug满天飞。说白了就是拿公众做测试肉鸡的版本,坐等0.12。

静态文件输出与nginx怎么样?

哈哈,又是你这位犀利哥,我比较喜欢你的评论,一针见血

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上两者还是有变化的,想要全部兼容还得费点力。

http://cnodejs.org/topic/51c3289573c638f370492f2e中有说明,相同的机器,相同的文件,相同的网络环境之间的测试结果

厉害,感觉iroute和ifile更加适合跟connect配合使用,选择使用express的同学估计不会考虑这些性能损耗

@snoopy 我觉得他说的流量是指有 10m ~ 100m 级别的pv 访问…

哈哈,感谢捧场啊~团队组建好了吗?

额,应该可以和connect整合把,没测试过

应该可以和connect一起使用吧,api差不多的。所以说你考虑的东西比较实际和实用,我都是弄些花哨的玩意,大都只能算储备没机会投入生产,唉~

@snoopy 为什么不生产呢?哈哈

使用时稍微复杂,如果能像简单地引入一个中间件就可以的,就方便多了。 比如这样: app.use(iroute()) 或者 iroute(app)

@sumory 呵呵,就看看数据自己意淫下,真正投入生产还是nginx了。。哈哈

我擦,有道理啊,我怎么没想到呢,不过这2个模块是给我们新框架flat用的,你不也在这个群里么,还有小问

@youxiachai pv数,是指日均pv吗?这个怎么测试?

对不起我无意泼冷水。我提的问题是假如ndoejs 的缓存真的不是那么理想,为什么不使用反向代理,代替这部分工作。

@snoopy 啥群,求加,咳咳…

@sumory @hexie 多人会话来的,不是QQ群

@leizongmin 高端大气上档次!

@sumory @hexie 这个讨论组就是在折腾一个新框架flat,也是小问发起的,我就是帮他打工的。好像讨论组能申请加入的吧?

哈哈,我就喜欢泼冷水的,听其他声音 1、nodejs缓存不理想是你打错字了吧,你是说静态文件响应不理想吧,静态文件建议公司生产环境还是用nginx或者cdn上去,但是个人网站什么的可能是nodejs空间,没有条件安装nginx的话还是只能使用nodejs来处理静态文件

2、反向代理主要工作是负载均衡,但是随之而带来的性能损耗也要计算在里面,反向代理应该使用在更适合的地方,单服务器我觉得没必要

@snoopy 是QQ的讨论组?貌似不行,只能邀请好友加入

@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);

@firstgeniusboy 语言层次的缓存能详细点说明吗?不明白你的意思啊。http 协议缓存ifile模块已经做掉了,当然线上比较成熟的应用静态资源还是分开比较好

@leizongmin 牛逼啊,有访问地址码?看看你用node做了什么?

@snoopy 大概9月份上线,现在还没做好,到时再告诉你吧

@snoopy nodejs 除了提供语言本身的缓存,还有其他什么吗?必须exports的缓存。

@snoopy 简单是简单了,但是我感觉现在的路由机制配置起来还是太繁琐了,类似java中struts的默认路由进制就比较好,比如说我一般url的组成形式是这样的http://host/controlname/functionName,这样的话就应该可以自动定位到控制器,控制器的方法,就不需要些这么繁琐的路由规则了,上只是个人想法。

@leizongmin 好的,上线告诉我啊

@dengqiao 这种方式不如路由表来的直观,而且你想在某几个action中加入中间过滤middleware也还是要写判断,是一种方式,各人各喜欢了,最早我就用过try catch方式直接require模块执行里面的方法,后来和大牛们聊了会还是发现这种路由清晰,更易项目维护和交接

@firstgeniusboy 语言本身的缓存,不明白你的意思啊~

@snoopy 看看我写的一个demo http://cnodejs.org/topic/51ca401d73c638f370ed104e,这种方式无论效率还规范上面还是强很多

@snoopy nodejs 对对象本身的缓存。比如模块exports 你的缓存指的是什么?

@snoopy 还在找,困难重重

@pengchun 加油~阿里巴巴的影响力应该可以找到很多大牛把

@firstgeniusboy 我的缓存指的是http协议的缓存,和你说的没关系,本文主要也是说静态资源和路由的,和nodejs的module缓存没关系的啊

@dengqiao 这种方式如果你想要对其中一些aciton做middleware过滤就比较麻烦了,还是得再入口处做url匹配,利用app.all注册的路由匹配归根到底还是利用js的正则判断。iroute路由是基于char*的strncmp,所以在执行效率方面要比js的正则快一些。 不过路由这东西各人各喜欢了,不必强求了

@snoopy 那你最开始特指什么nodejs 缓存。其实我一直觉得Nodejs 做涉及文件处理的东西是个很蛋疼的事情。http 协议缓存不就是浏览器缓存吗。不知道你用这个做过什么东西测试一下正确性吗?

回到顶部