Node.js redis订阅内存泄漏

时间:2014-01-10 22:29:24

标签: node.js redis

我是“Server-Side JS”的新手,找不到使用node.js和Redis-Sub进行长轮询的示例。

以下代码运行良好,但今天我注意到RAM使用量为650MB,代码只运行了6天。

var http     = require('http'),
    redis    = require('redis'),
    client   = redis.createClient();

client.subscribe("example");

http.createServer(function (req, res) {

    res.setHeader('Access-Control-Allow-Origin', 'https://mywebsite.com');
    res.setHeader('Access-Control-Allow-Methods', 'GET');
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
    res.setHeader('Access-Control-Allow-Credentials', true);

    res.writeHead(200, {'Content-Type': 'application/json'});

    client.on("message", function (channel, message) {

        res.end( JSON.stringify( message ) );

    });

}).listen(8080);

有人可以指出内存泄漏并解释一下吗?

我的node.js版本是:v0.10.21

3 个答案:

答案 0 :(得分:2)

“内存泄漏”来自代码client.on。你在请求/响应函数中调用它。 client.on是一个发射器(请参阅redis源,index.js:111(截至今天的npm安装))并使用

定义函数on
  

将侦听器添加到指定事件的侦听器数组的末尾。 (Nodejs-Docs:1

所以你不断向客户端添加"message" - 函数。将client.on移到此请求/响应 - “循环”之外,它应该停止“泄漏”。

答案 1 :(得分:1)

以下内容在逻辑上符合您的要求,请从此处开始:

var http     = require('http'),
    redis    = require('redis'),
    client   = redis.createClient();

client.subscribe("example");

var responses = [];

client.on('message', function(channel, message) {
    var res;
    while (responses.length) {
        res = responses.pop();
        res.end(JSON.stringify(message));
    }
});

http.createServer(function (req, res) {

    res.setHeader('Access-Control-Allow-Origin', 'https://mywebsite.com');
    res.setHeader('Access-Control-Allow-Methods', 'GET');
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
    res.setHeader('Access-Control-Allow-Credentials', true);

    res.writeHead(200, {'Content-Type': 'application/json'});

    responses.push(res);

}).listen(8080);

当您继续接收尚未满足消息和end() ed的请求时,您的内存需求将会增长,但除此之外,此处不会发生很多事情。任何真正的内存泄漏都必须从组件模块中引入。

答案 2 :(得分:0)

右。我想我现在明白了这一点,但纠正我,如果我错了:redis客户端发出定期更新,告知确切的数据。 (因此,如果它永远不会改变,它将继续定期发送相同的消息。)使用当前代码,客户端可以向您的服务器发送请求,并接收redis服务器内容的更新。但是客户端必须等到下次服务器从redis获得更新时才会这样做。

客户必须等待的事实感觉不对。我认为它应该立即发送一个响应与从redis收到的最后一次更新。这可以通过一些修改来实现:

var http     = require('http'),
    redis    = require('redis'),
    client   = redis.createClient();

var lastMessage = null;

client.subscribe("example");

client.on("message", function (channel, message) {

    lastMessage = message

});

http.createServer(function (req, res) {

    res.setHeader('Access-Control-Allow-Origin', 'https://mywebsite.com');
    res.setHeader('Access-Control-Allow-Methods', 'GET');
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
    res.setHeader('Access-Control-Allow-Credentials', true);

    res.writeHead(200, {'Content-Type': 'application/json'});

    res.end( JSON.stringify( lastMessage ) );

}).listen(8080);

并且上面的代码也没有重复设置redis处理程序,所以它不应该泄漏内存。

我可以看到的一个缺点是,如果客户端在节点从redis听到之前要求更新,它将收到null。在这个(可能是不寻常的)情况下,在回复之前等待redis可能会更好。

如果这让您感到困扰,可以将行res.end( JSON.stringify( lastMessage ) );替换为“如果您已经从redis中听过,那么res.end( JSON.stringify( lastMessage ) );;否则,设置处理程序以在redis发送时执行此操作信息”。处理程序应设置为只运行一次,然后删除;您可以使用.once代替.on来完成此操作。

相关问题