2014-01-10 58 views
2

我是「服務器端JS」的新手,找不到使用node.js和Redis-Sub進行長輪詢的示例。Node.js redis訂閱內存泄漏

下面的代碼運行良好,但今天我注意到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

+0

函數'function(req,res)'在服務器收到請求時運行。每次運行時,一個處理程序由'client.on(「message」,...)'設置。這些處理程序不會被刪除;因此每次收到請求時內存使用率都會增加。 不僅如此,每次redis客戶端收到一條消息時,都會運行function(channel,message)函數。如果'res'已經被髮送,推測它不會做任何事情,但是如果有許多處理程序,這可能會導致大量的開銷。 (在這種情況下,您會看到處理每個請求的延遲。) –

+0

結帳:http://book.mixu.net/node/ch3.html – bryanmac

+0

您想做什麼?我大致瞭解我認爲它會做什麼,我看不出有任何合理的理由。客戶端請求和Redis數據之間的連接是什麼? –

回答

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來做到這一點。

+0

Redis訂閱的作品就像您正在訂閱頻道並等待新消息。而我的代碼正在用'.on(「message,'function)等待新消息。當新消息到來時,它會推動並關閉連接。 – xecute

+0

我認爲是這樣,但我的觀點是:用你的代碼版本,客戶端向你的服務器發送請求必須等到你的服務器下一次從redis獲得消息時,我認爲這不是你想要的,所以我重寫了它,以便服務器立即迴應從redis收到的_previous_消息但如果我錯了,而且確實想讓客戶端等待,那麼請忽略我的回答,然後嘗試將'client.on(「message」,...)'改爲'client.once(「message」,。如果你想要別的東西,請詳細說明。 –

+0

我用'client.once'加載測試它,它仍然線性增加(從45MB開始,在GC下降到50MB後打到80-85MB,然後打到90-95MB,GC下降到60MB後......) – xecute

2

「內存泄漏」來自代碼client.on。你可以在請求/響應函數中調用它。 client.on是發射極(見redis的源,index.js:111(如今天的NPM安裝的))和限定函數on

添加一個偵聽聽衆陣列爲指定事件的結束。 (Nodejs-Docs:1

因此,您不斷向客戶端添加"message"函數。將client.on移到這個請求/響應 - 「循環」之外,它應該停止「泄漏」。

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()請求您的存儲需求將增長但除此之外,這裏並沒有太多的事情要做。任何真正的內存泄漏都必須從組件模塊中引入。