下面是我正在尝试做的事情:我正在开发一个Node.js http服务器,它将在一台机器中保存来自数万个移动客户机的长连接,以实现推送目的(与redis协作)。
测试环境:
1.80GHz*2 CPU/2GB RAM/Unbuntu12.04/Node.js 0.8.16
第一次,我使用了“Express”模块,在使用swap之前,我可以达到大约120K的并发连接,这意味着RAM不够。然后,我切换到本地“HTTP”模块,我得到了大约160K的并发。但是我意识到仍然有太多的功能我不需要在原生http模块,所以我把它切换到原生“NET”模块(这意味着我需要自己处理http协议,但没关系)。现在,我可以达到每台机器大约250K的并发连接。
下面是我的代码的主要结构:
var net = require('net');
var redis = require('redis');
var pendingClients = {};
var redisClient = redis.createClient(26379, 'localhost');
redisClient.on('message', function (channel, message) {
var client = pendingClients[channel];
if (client) {
client.res.write(message);
}
});
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);
var req = {
clientId: 'whatever'
};
var res = new ServerResponse(socket);
server.emit('request', req, res);
}
}
});
server.on('request', function (req, res) {
if (res.socket.destroyed) {
return;
}
pendingClinets[req.clientId] = {
res: res
};
redisClient.subscribe(req.clientId);
res.socket.on('error', function (err) {
console.log(err);
});
res.socket.on('close', function () {
delete pendingClients[req.clientId];
redisClient.unsubscribe(req.clientId);
});
});
server.listen(3000);
function ServerResponse(socket) {
this.socket = socket;
}
ServerResponse.prototype.write = function(data) {
this.socket.write(data);
}
最后,以下是我的问题:
>
如何减少内存使用从而进一步提高并发性?
我担心内存泄漏,尽管我已经做了一些测试,似乎没有问题。有什么我应该关心的问题或建议吗?
我发现了一个关于V8隐藏类的文档,正如它所描述的那样,这是否意味着每当我像上面的代码一样向我的全局对象pendingClients添加一个由clientId命名的属性时,就会生成一个新的隐藏类?会导致内存泄漏吗?
编辑:我是如何运行加载测试的?
1。首先,我修改了服务器和客户机上的一些参数(要实现60K以上的并发需要多台客户机,因为一台客户机最多只有60K+端口(用16位表示))
1.1。对于服务器和客户机,我修改了文件描述符,在运行测试程序的shell中使用以下命令:
ulimit -Hn 999999
ulimit -Sn 999999
1.2.在服务器机器上,我还修改了一些NET/TCP相关的内核参数,最重要的有:
net.ipv4.tcp_mem = 786432 1048576 26777216
net.ipv4.tcp_rmem = 4096 16384 33554432
net.ipv4.tcp_wmem = 4096 16384 33554432
1.3.对于客户端计算机:
net.ipv4.ip_local_port_range = 1024 65535
2.其次,我使用Node.js编写了一个自定义的模拟客户端程序,因为大多数负载测试工具,ab和siege等都是针对短连接的,但我使用的是长连接,并且有一些特殊的要求。然后我在一台机器上启动了服务器程序,在另外三台独立的机器上启动了三个客户端程序。
编辑:我确实在一台机器(2GB RAM)上达到了250K的并发连接,但事实证明,这并不是很有意义和实用。因为当连接连接时,我只是让连接挂起,没有别的。当我试图向它们发送响应时,并发数下降到150K左右。正如我计算的那样,每个连接的内存使用量大约增加了4KB,我想这与net.ipv4.tcp_wmem有关,我将其设置为4096 16384 33554432,但即使我将其修改为更小,也没有任何变化。我想不出为什么。
编辑:实际上,现在我更感兴趣的是每个tcp连接使用多少内存,以及单个连接使用的内存的确切组成是什么?根据我的测试数据:
150K并发消耗了大约1800M RAM(来自Free-M输出),Node.js进程有大约600M RSS
然后,我假设是这样的:
600M/150K=4K,这是单个连接的Node.js内存使用情况
我说的对吗?我怎样才能减少这两方面的内存使用量?
如果有什么地方我没有描述好,让我知道,我会细化的!如有任何解释或建议,将不胜感激,谢谢!
>
我认为您不应该担心内存使用进一步减少。从所包含的读数来看,似乎非常接近可想象的最小值(我将其解释为以字节为单位,当没有指定单位时,这是标准的)。
这是一个我无法回答的更深入的问题,但以下是什么RSS。据我所知,堆是unix系统中动态分配内存的来源。因此,堆总数似乎是为您的使用分配在堆上的所有内容,而使用的堆是您使用了多少分配的内容。
你的内存使用情况很好,而且看起来你实际上没有漏洞。我还不担心。=]
不知道。
这张快照似乎很合理。我希望从激增的请求中创建的一些对象已经被垃圾收集,其他的没有。你可以看到没有超过10K的对象,这些对象中的大多数都很小。我称之为好。
不过,更重要的是,我想知道您是如何对此进行负载测试的。我以前尝试过进行类似的大规模负载测试,大多数工具都无法在linux上生成这样的负载,因为打开的文件描述符的数量受到限制(默认情况下每个进程大约有1000个)。同样,一旦使用了套接字,就不能立即再次使用。我记得,这需要很长一分钟才能再次使用。在这一点上,我通常看到系统范围内的打开文件描述符限制设置在100K以下,我不确定是否可能在未修改的盒子上接收如此大的负载,或者在单个盒子上生成它。由于您没有提到任何这样的步骤,我认为您可能还需要调查负载测试,以确保它按照您的想法进行。
问题内容: 我们知道node.js为我们提供了强大的功能,但强大的功能带来了巨大的责任。 据我所知,V8引擎不进行任何垃圾收集。因此,我们应该避免什么最常见的错误,以确保没有内存从节点服务器泄漏。 编辑: 对不起,V8确实具有强大的垃圾收集器。 问题答案: 据我所知,V8引擎不进行任何垃圾收集。 V8内置了强大而智能的垃圾收集器。 您的主要问题是不了解闭包如何维护对外部函数的范围和上下文的引用。这
问题内容: 我正在设计一个Web应用程序,该应用程序旨在显示一堆使用AJAX定期更新的数据。一般的使用场景是用户将整天保持打开状态,然后不时浏览一下。 我遇到的问题是浏览器的内存占用量随时间缓慢增长。Firefox和IE 7(尽管不是Chrome)都在发生这种情况。几个小时后,它可能导致IE7占用约200MB的内存,而FF3导致占用约400MB的内存。 经过大量测试,我发现只有在响应AJAX调用时
一、内存溢出 一种程序运行出现的错误。 当程序运行需要的内存超过了剩余的内存时, 就出抛出内存溢出的错误。 二、内存泄漏 占用的内存没有及时释放。 内存泄露积累多了就容易导致内存溢出。 常见的内存泄露: 意外的全局变量。 没有及时清理的计时器或回调函数。 闭包 // 1. 内存溢出 var obj = {} for (var i = 0; i < 10000; i++) { obj[i] =
问题内容: 我正在尝试追踪Node.js应用程序中的内存泄漏。我已经尝试安装v8-profiler,但无法编译…看起来像一个死项目,很多人都在尝试使用它,但是遇到了同样的问题- 大约在节点0.3.2上已经很多了前。 有谁知道一种不使用v8-profiler来查找Node.js应用程序中的内存泄漏的方法吗?我在运行V8远程调试的Eclipse上运行,但是找不到找到内存使用情况/堆等的方法。 问题答案
我担心从泄漏金丝雀回来的信息。它显示了在UI上声明的所有变量,如片段中的材料按钮、材料卡片视图、文本视图、图像视图等,都导致了内存泄漏。我不知道为什么会这样。
问题内容: 我的socket.io版本是socket.io@0.8.7和redis@0.7.1。我在Windows上。 在某些地方,我已经看到问题已解决。我想我正在使用最新的socket.io版本。什么是generator.setMaxListeners(),在哪里可以设置? 我正在使用redis pubsub,当我订阅redis时,它会抛出此警告。 问题答案: 有一个与此相关的已知问题。好像是几