我使用websockets传输视频文件,这意味着它们是大文件。服务器端(以及客户端)使用nodejs实现,javascript中使用binaryjs。
它工作得很好,直到我开始有大量的客户端,什么使服务器崩溃(进程被Linux操作系统杀死)。正如我所观察到的,它耗尽了内存,因为对于每个客户端,它都占用了很多内存,但问题是,当客户端断开连接时,这些内存不会被释放。我认为这应该在内部完成,我不应该担心内存,我错了吗?我可能做错了什么吗?
正如我所看到的,"send"函数保留内存来保存它必须发送的内容,但从不释放内存。(如果你注释那一行,没有内存问题)下面是代码:
var fs = require('fs');
var BinaryServer = require('binaryjs').BinaryServer;
var bs = BinaryServer({port: 8080});
var nchunks=116;
bs.on('connection', function(client){
for(var i=1; i<=nchunks; i++)
{
var name="/var/www/1.m4s";
var fd=fs.openSync(name.replace("1.m4s", i+".m4s"), 'r');
var buf = new Buffer(fs.fstatSync(fd).size, 'binary');
fs.readSync(fd, buf, 0, buf.length, null)
client.send(buf);
fs.closeSync(fd);
if(i==nchunks){
client.send("end");
}
}
client.on('close', function(c){
console.log("closing");
});
});
当客户端接收到所有的视频文件时,关闭套接字,所以我知道它正在关闭,因为我在服务器上捕获"close"事件。它不应该在这个时候释放内存吗?
最糟糕的是,因为我找不到错误,我认为这可能是由于binaryjs如何实现它,所以我也尝试了"ws"one_answers"websocket-node"在内存中具有相同的结果。
有人遇到过这个问题吗?任何想法?
不应该在这个时候释放内存
不,JavaScript是一种垃圾回收语言,垃圾回收器在运行时认为合适时定期运行。您无法控制或意识到它何时或是否会运行,从而释放内存。
同样,你不能在网络服务器上使用任何同步IO调用,因为当你执行每个IO调用时,所有的客户端处理都会阻塞。
我认为你的主要问题是你没有按合理的小块流式传输文件。您正在尝试将整个文件读入内存并将其发送。
var buf = new Buffer(fs.fstatSync(fd).size, 'binary');
不要那样做。使用ReadableStream并以一系列小块发送文件,并使用异步调用。这就是如何让节点为您正确工作。缺少流和异步调用肯定会导致节点故障。下面是一个工作示例程序。
var fs = require("fs");
var http = require("http");
var server = http.createServer();
server.listen(9200)
server.on('request', function (req, res) {
fs.createReadStream('/tmp/test1').pipe(res);
});
我在OSX上对节点v0.10.7进行了测试,我可以反复请求curl localhost:9200 >/dev/null
文件并观看lsof -p <pid of node>
,我可以看到/tmp/test
文件被正确打开和关闭。