给 connect 的 static 模块加上url路径前缀

2012-07-14 18:06

给 connect 的 static 模块加上url路径前缀

by 司徒正美

at 2012-07-14 10:06:00

original http://www.cnblogs.com/rubylouvre/archive/2012/07/14/2591139.html

估计我们使用 connect 都会很自然地按照官方的例子使用静态文件模块 static:

var connect = require('connect');connect(  connect.static(__dirname),  function (req, res) {    res.writeHead(200, {'Content-Type': 'text/plain'});    res.end('Hello World\n');  }).listen(8124);console.log('Server running at http://127.0.0.1:8124/');

基准性能

为了评测 static 的性能,我们需要又一个基准对比。

官方最纯洁的 helloworld

我们使用 nodejs 官方文档给出的 helloworld 做最基础的参照:

ar http = require('http');http.createServer(function (request, response) {  response.writeHead(200, {'Content-Type': 'text/plain'});  response.end('Hello World\n');}).listen(8124);console.log('Server running at http://127.0.0.1:8124/');

最纯洁的 connect helloworld

不使用任何中间件模块

var connect = require('connect');connect(function (req, res) {  res.writeHead(200, {'Content-Type': 'text/plain'});  res.end('Hello World\n');}).listen(8124);console.log('Server running at http://127.0.0.1:8124/');

结合 domain 模块的 connect helloworld

var connect = require('connect');var createDomain = require('domain').create;connect(  function (req, res, next) {    var domain = createDomain();    domain.on('error', function (err) {      console.log('errrrrr', err);      res.statusCode = 500;      res.end(err.message + '\n');      domain.dispose();    });    domain.run(next);  },  function (req, res, next) {    if (req.url === '/error') {      process.nextTick(function () {        res.end('params: ' + req.query.abc);      });      return;    }    res.writeHead(200, {'Content-Type': 'text/plain'});    res.end('Hello World\n');  }).listen(8124);console.log('Server running at http://127.0.0.1:8124/');

测试结果

官方最纯洁的 helloworld: 7851.56 qps

$ siege -b -c10 -t10S http://127.0.0.1:8124/** SIEGE 2.72** Preparing 10 concurrent users for battle.The server is now under siege...Lifting the server siege...      done.Transactions:          78123 hitsAvailability:         100.00 %Elapsed time:           9.95 secsData transferred:         0.89 MBResponse time:            0.00 secsTransaction rate:      7851.56 trans/secThroughput:           0.09 MB/secConcurrency:            9.93Successful transactions:       78123Failed transactions:             0Longest transaction:          0.09Shortest transaction:         0.00

最纯洁的 connect helloworld: 6808.19 qps

$ siege -b -c10 -t10S http://127.0.0.1:8124/** SIEGE 2.72** Preparing 10 concurrent users for battle.The server is now under siege...Lifting the server siege...      done.Transactions:          78123 hitsAvailability:         100.00 %Elapsed time:           9.95 secsData transferred:         0.89 MBResponse time:            0.00 secsTransaction rate:      7851.56 trans/secThroughput:           0.09 MB/secConcurrency:            9.93Successful transactions:       78123Failed transactions:             0Longest transaction:          0.09Shortest transaction:         0.00

使用 domain 模块的 connect helloworld: 5601.35 qps

domain demo for express

$ siege -b -c10 -t10S http://127.0.0.1:8124/** SIEGE 2.72** Preparing 10 concurrent users for battle.The server is now under siege...Lifting the server siege...      done.Transactions:          65699 hitsAvailability:         100.00 %Elapsed time:           9.65 secsData transferred:         0.75 MBResponse time:            0.00 secsTransaction rate:      6808.19 trans/secThroughput:           0.08 MB/secConcurrency:            9.96Successful transactions:       65699Failed transactions:             0Longest transaction:          0.05Shortest transaction:         0.00

带 static 的 connect helloworld: 3636.98 qps

$ siege -b -c10 -t10S http://127.0.0.1:8124/** SIEGE 2.72** Preparing 10 concurrent users for battle.The server is now under siege...Lifting the server siege...      done.Transactions:          34915 hitsAvailability:         100.00 %Elapsed time:           9.60 secsData transferred:         0.40 MBResponse time:            0.00 secsTransaction rate:      3636.98 trans/secThroughput:           0.04 MB/secConcurrency:            9.97Successful transactions:       34915Failed transactions:             0Longest transaction:          0.06Shortest transaction:         0.00

为什么性能降低了50%

晕,为什么加上了 static 模块,性能会降低了50%这么多?

查看 static.send() 源代码:

// "hidden" fileif (!hidden && '.' == basename(path)[0]) return next();fs.stat(path, function(err, stat){  // mime type  type = mime.lookup(path);  // ignore ENOENT  if (err) {    if (fn) return fn(err);    return ('ENOENT' == err.code || 'ENAMETOOLONG' == err.code)      ? next()      : next(err);  // redirect directory in case index.html is present  } else if (stat.isDirectory()) {    if (!redirect) return next();    res.statusCode = 301;    res.setHeader('Location', url.pathname + '/');    res.end('Redirecting to ' + url.pathname + '/');    return;  }

static 模块每次都需要一次文件IO,判断文件是否存在,这是多么损耗性能啊。

增加静态文件url路径前缀

既然找到性能问题所在,就可以解决此问题了。对症下药,无需让所有请求都经过 static 处理即可。

给 static 增加一个url前缀判断,例如 /public/images/logo.jpg 只有前缀是 /public 的 url 请求才需要进入 static 模块处理。

那么我们改进后的代码应该是这样的:

var connect = require('connect');var app = connect();app.use('/public', connect.static(__dirname));app.use(function (req, res) {  res.writeHead(200, {'Content-Type': 'text/plain'});  res.end('Hello World\n');}).listen(8124);console.log('Server running at http://127.0.0.1:8124/');

性能如何? wow 6749.03 qps, 几乎和 connect hellowrold 一致。done!

$ siege -b -c10 -t10S http://127.0.0.1:8124/** SIEGE 2.72** Preparing 10 concurrent users for battle.The server is now under siege...Lifting the server siege...      done.Transactions:          66073 hitsAvailability:         100.00 %Elapsed time:           9.79 secsData transferred:         0.76 MBResponse time:            0.00 secsTransaction rate:      6749.03 trans/secThroughput:           0.08 MB/secConcurrency:            9.97Successful transactions:       66073Failed transactions:             0Longest transaction:          0.03Shortest transaction:         0.00

重现一下之前的性能问题,访问 /public/foo 即可重现。

$ siege -b -c10 -t10S http://127.0.0.1:8124/public/foo** SIEGE 2.72** Preparing 10 concurrent users for battle.The server is now under siege...Lifting the server siege...      done.Transactions:          37773 hitsAvailability:         100.00 %Elapsed time:           9.59 secsData transferred:         0.43 MBResponse time:            0.00 secsTransaction rate:      3938.79 trans/secThroughput:           0.05 MB/secConcurrency:            9.97Successful transactions:       37773Failed transactions:             0Longest transaction:          0.05Shortest transaction:         0.00

有爱

记得给 connect.static 加上一个url路径前缀喔!

^_^ 希望本文对你有用。

原贴的链接

本文链接