25658210
我在做长连接服务器的时候遇到些问题,stackoverflow链接
现在平均下来每个连接占12k多的内存,感觉还不是很理想(希望降到8k以下),谁能指点下(linux内核调优方面和node.js代码方面等)? 谢谢!
另外搜集资料的时候,发现这种场景以下几种技术用得也比较多:c/c++(libev,libeio)(当然node.js底层也是他们),Java NIO,erlang,有哪位大神做过得,可否分享下经验?相比起来,哪种更有优势?或者谁对这几种方案比较熟悉,做个demo来跟node.js比一下?
2013-1-8: 做了以下测试,发现一些奇怪的现象:
| 序号 | 并发量(万) | free -m(used -buffers/cache) | node.js RSS | 描述 |
|---|---|---|---|---|
| 1 | 6 | 500 | 210 | 无sendResonse,无cacheSocket |
| 2 | 6 | 578 | 290 | 无sendResonse,有cacheSocket |
| 3 | 6 | 822 | 290 | 有sendResonse,有cacheSocket |
sendResonse,cacheSocket见下面代码:
var net = require('net');
var pendingClients = {};
var clientsCount = 0;
var server = net.createServer(function (socket) {
var buffer = '';
socket.setEncoding('utf-8');
socket.on('data', onData);
function onData(chunk) {
buffer += chunk;
// Parse request data.
// ...
if ('I have got all I need') {
socket.removeListener('data', onData);
// Doing this to provide the same interface with official http module
var req = {
clientId: 'whatever'
};
var res = new ServerResponse(socket);
server.emit('request', req, res);
}
}
});
server.on('request', function (req, res) {
// Other business logic
// ...
clientsCount++
console.log(clientsCount);
sendResponse(res);
cacheSocket(req, res);
});
server.listen(3000);
// Custom ServerResponse
function ServerResponse(socket) {
this.socket = socket;
}
ServerResponse.prototype.write = function(data) {
if (this._headerSent) {
// Send http header
// ...
this._headerSent = true;
}
// Parse data to 'Transfer-Encoding: chunked'
// ...
this.socket.write(data);
}
function sendResponse(res) {
res.write('PING');
}
function cacheSocket(req, res) {
pendingClients[req.clientId] = {
res: res
};
res.socket.on('error', function (err) {
console.log(err);
});
res.socket.on('close', function () {
delete pendingClients[req.clientId];
clientsCount--;
});
}
问题:
- 3和2相比,RSS不变,也就是说用于内核TCP栈的内存多了200多M,平均每个连接多了接近4k,我怀疑是内核socket的send buffer,但是调整net.ipv4.tcp_wmem不起作用?如果是send buffer,为何发送响应之前没有出现,难道是只有发送数据时才开辟吗?网上实在是找不到资料能解释这个问题了……
- 2和1相比,不缓存node.js生成的socket对象,省了80M左右,我打算采用@codekiller的建议,直接操作handle,肯看效果怎么样,后面会把结果放上来
- 还有一个十分诡异的问题,关于net.ipv4.tcp_mem。当该值设置为:48120 64161 96240(单位是page,一个page4KB,刚好是tcp_wmem和tcp_rmem的最小值)(Ubuntu12.04默认值)时,采用第一种测试方法,最多只能压进96238个并发连接,再多一个,整个server的tcp连接都会停止响应,ssh都连不进去,这肯定跟net.ipv4.tcp_mem的最大值96240有关,但是sendResponse时,却没有这个问题,实在想不通,何解?
2013-1-12 采用@codekiller的建议后,直接使用handle,每6万连接大概省下100M内存,在此表示感谢!
但是对TCP socket的receive buffer和send buffer还是没弄明白,如何进一步优化?以及上面的诡异现象是什么原因?
最近打算看一下底层的libuv,因为感觉javascript层面已经没什么可做的了,希望能从底层找到突破口(比如直接设置socket的buffer值,现在好像没有这个接口,看看自己能不能加上)
欢迎大家发表意见,谢谢!