大家都知道用Node.js搭建一個簡單的http服務器是多么easy的事情庐橙,打開記事本貼幾句腳本命黔,ctrl+s一下澜沟,node server.js 一個http服務器就這樣跑起來了够坐,別看它簡單托嚣,但性能絲毫不差损趋。
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello Worldn');
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');
Node.js搭建的服務器性能如此給力確實讓我很好奇它的內(nèi)部是如何設計的患久,忍不住翻了翻lib下的代碼。
深入了解過Node.js http模塊的同學應該知道Node.js采用一個純c寫的http_parser來實現(xiàn)對http報文的解析浑槽,暴露到Node.js上的是一個HTTPParser對象蒋失,在Node.js中用下面一句代碼即可拿到
var HTTPParser = process.binding('http_parser').HTTPParser;
Node.js中調(diào)用c/c++內(nèi)置模塊采用 process.binding('module')模式,比如我們常用的setInterval和setTimeout都是基于c/c++代碼實現(xiàn)桐玻,用 process.binding('timer_wrap').Timer即可提供js調(diào)用篙挽。
Node.js http服務器每收到一個request就會用一個HTTPParser對象來解析出請求信息,比如請求參數(shù)镊靴,請求體之類的铣卡。如果說每接收一個request 都new 一個 HTTPParser對象來處理, 可以想象當并發(fā)達到成千上萬時創(chuàng)建HTTPParser對象是多么的頻繁,用完之后又立刻銷毀偏竟,這種場景我們很容易想到利用多線程來處理耗時任務煮落,為了避免頻繁的創(chuàng)建銷毀線程對象, 一般都會創(chuàng)建一個線程池來處理任務。于是Node.js中邊產(chǎn)生了對象池這么個東西,也就是接下來要講的freelist 踊谋。
首先我們來看看freelist是個什么東西蝉仇,和對象池有怎樣的聯(lián)系。
function FreeList(name, max, constructor) {
this.name = name;
this.constructor = constructor;
this.max = max;
this.list = [];
};
FreeList.prototype.alloc = function() {
return this.list.length ? this.list.shift() :
this.constructor.apply(this, arguments);
};
FreeList.prototype.free = function(obj) {
//debug("free " + this.name + " " + this.list.length);
if (this.list.length < this.max) {
this.list.push(obj);
}
};
代碼相當?shù)暮唵瓮首樱現(xiàn)reeList構(gòu)造函數(shù)接收3個參數(shù)量淌,對象池名字,大小以及對象構(gòu)造函數(shù)嫌褪。比如在Node.js中創(chuàng)建一個httpParse對象池:
var parsers = new FreeList('parsers', 1000, function() {
var parser = new HTTPParser(HTTPParser.REQUEST);
parser._headers = [];
parser._url = '';
parser[kOnHeaders] = parserOnHeaders;
parser[kOnHeadersComplete] = parserOnHeadersComplete;
parser[kOnBody] = parserOnBody;
parser[kOnMessageComplete] = parserOnMessageComplete;
return parser;
});
Node.js中用這段代碼創(chuàng)建了一個叫parsers,大小為1000的對象池呀枢,當Node.js服務器接收到一個request時便向這個對象池索取一個HTTPParser對象即調(diào)用對象池parsers的alloc方法,此時便拿到了一個parser對象笼痛,parser對象解析完http報文后node并沒有立即釋放它裙秋,而是將它重新放入對象池parsers中,即調(diào)用parsers.free(parser),當然了只有當池子還沒滿的時候才可以重新被放進去缨伊。如此便實現(xiàn)了parser對象的重復利用摘刑,當并發(fā)數(shù)很高時極大的提升性能。
相信小伙伴們應該都很清楚對象池的原理以及它在Node.js服務器中的作用了刻坊, 希望對大家在實際的業(yè)務中有所幫助哦~
參考文檔
1.https://github.com/joyent/node/tree/master/deps/http_parser
2.https://github.com/joyent/node/blob/master/lib/freelist.js