2012-01-16 51 views
13

在的node.js應用程序我使用的KUE排隊庫,這是Redis的支持。當一項工作完成後,我將其從隊列中刪除。在夜間運行大約70,000個工作後,redis內存使用量大約爲30MB。數據庫中仍有18個失敗的作業,並且隊列長度當前爲零 - 作業處理速度比排隊更快。 Redis沒有以任何其他方式使用。使用Node.js的中Redis的支持「KUE」庫 - 爲什麼我的Redis的內存使用量不斷增加?

爲什麼Redis的內存使用量不斷即使我刪除完成的作業增加任何想法? CoffeeScript的代碼:

gaemodel.update = (params) -> 
    job = jobs.create "gaemodel-update", params 
    job.attempts 2 
    job.save() 
    job.on "complete", -> 
    job.remove (err) -> 
     throw err if err 
     console.log 'completed job #%d', job.id 

回答

0

其實這個問題是使用舊版本的節點。升級到0.6.x鏈解決了內存消耗問題。

19

當你有一個內存消耗問題與一個排隊系統,你是100%肯定,所有排隊的項目已被從商店移除,不坐成一個異常/錯誤隊列,那麼最可能的原因是排隊率遠高於出隊率。

的Redis使用通用內存分配器(jemalloc,ptmalloc,tcmalloc,等...)。這些分配器不一定會將內存送回系統。當一些內存被釋放時,分配器往往會保留它(重用它以用於未來的分配)。當許多小對象被隨機分配時,尤其如此,Redis通常是這種情況。

結果是在給定時間點的內存消耗的峯值會導致Redis的累積內存,並保持它。這個內存不會丟失,如果出現內存消耗的另一個峯值,它將被重用。但從系統角度來看,內存仍然分配給Redis。對於一個排隊系統,如果你排列物品的速度比你能夠將它們排出的速度快,你將在內存消耗上達到這樣的高峯。

我的建議是儀器應用程序以定期的時間間隔獲取和記錄隊列長度,以檢查隊列中項目數量的演變(並識別峯值)。

更新時間:

我已經測試了一些東西與KUE瞭解什麼是存儲在Redis的。實際上,數據結構非常複雜(字符串,集合,zsets和散列)。如果你看看Redis的,你會發現以下內容:

q:job:nnn    (hash, job definition and properties) 

q:search:object:nnn (set, metaphone tokens associated to job nnn) 
q:search:word:XXXXX (set, reverse index to support job full-text indexing) 

q:jobs:inactive  (zset, all the unprocessed jobs) 
q:jobs:X:inactive  (zset, all the unprocessed jobs of job type X) 

q:jobs:active   (zset, all the on-going jobs) 
q:jobs:X:active  (zset, all the on-going jobs of job type X) 

q:jobs:complete  (zset, all the completed jobs) 
q:jobs:X:complete  (zset, all the completed jobs of job type X) 

q:jobs:failed   (zset, all the failed jobs) 
q:jobs:X:failed  (zset, all the failed jobs of job type X) 

q:jobs:delayed  (zset, all the delayed jobs) 
q:jobs:X:delayed  (zset, all the delayed jobs of job type X) 

q:job:types   (set, all the job types) 
q:jobs    (zset, all the jobs) 

q:stats:work-time  (string, work time statistic) 
q:ids     (string, job id sequence) 

我不知道CoffeeScript的好,所以我嘗試使用普通的舊JavaScript來重現問題:

var kue = require('kue'), 
    jobs = kue.createQueue(); 

jobs.process('email', function(job,done) { 
    console.log('Processing email '+JSON.stringify(job)) 
    done(); 
}); 

function create_email(i) { 
    var j = jobs.create('email', { 
    title: 'This is email '+i 
    , to: 'didier' 
    , template: 'Bla bla bla' 
    }); 
    j.on('complete', function() { 
    console.log('complete email job #%d', j.id); 
    j.remove(function(err){ 
     if (err) throw err; 
     console.log('removed completed job #%d', j.id); 
    }); 
    }); 
    j.save(); 
} 

for (i=0; i<5; ++i) 
{ 
    create_email(i); 
} 

kue.app.listen(8080); 

我跑這代碼,檢查什麼留在Redis的處理後:

redis 127.0.0.1:6379> keys * 
1) "q:ids" 
2) "q:jobs:complete" 
3) "q:jobs:email:complete" 
4) "q:stats:work-time" 
5) "q:job:types" 
redis 127.0.0.1:6379> zrange q:jobs:complete 0 -1 
1) "1" 
2) "2" 
3) "3" 
4) "4" 
5) "5" 

因此,似乎已完成作業被保存在問:工作:完全和q:工作:X:完全不顧工作已被刪除。我建議你在你自己的Redis實例中檢查這些zset的基數。

我的解釋是這些zset的管理髮生在之後發出'completed'事件。所以這些作業被正確刪除,但他們的id被插入到那些zsets中。

解決方法是避免依賴每個作業事件,而是使用每個隊列事件來刪除作業。例如,下面的修改是可以做到:

// added this 
jobs.on('job complete', function(id) { 
    console.log('Job complete '+id) 
    kue.Job.get(id, function(err, job) { 
    if (err) return; 
    job.remove(function(err){ 
     if (err) throw err; 
     console.log('removed completed job #%d', job.id); 
    }); 
    }); 
}); 

// updated that 
function create_email(i) { 
    var j = jobs.create('email', { 
    title: 'This is email '+i 
    , to: 'didier' 
    , template: 'Bla bla bla' 
    }); 
    j.save(); 
} 

固定程序後,在Redis的內容要好得多:

redis 127.0.0.1:6379> keys * 
1) "q:stats:work-time" 
2) "q:ids" 
3) "q:job:types" 

你或許可以使用類似的策略,從Coffescript。

+0

喜迪迪埃 - 感謝這個答案,但我不認爲它標識問題。我應該提到隊列長度爲零。可以很容易地監控這個KUE庫隊列狀態 - 它包括一個內置的管理服務器和前端。我將編輯我的問題以添加此信息。 – mainsocial 2012-01-17 00:01:57

+0

我已經相應地更新了我的答案。 – 2012-01-17 17:31:25

+0

迪迪埃 - 感謝您的調查。我獨立地得出了很多相同的結論。事實上,我能夠修復kue代碼中的一些錯誤。我已將修復程序簽入我的fork並提出了請求。 – mainsocial 2012-01-27 23:54:57

2

很高興見到你能解決問題。在任何情況下,下一次你有Redis的內存問題,您的第一個停靠港應該是「INFO」 Redis的命令。這個命令會告訴你有用的信息,如

內存

used_memory:3223928 used_memory_human:3.07M used_memory_rss:1916928 used_memory_peak:3512536 used_memory_peak_human:3.35M used_memory_lua:37888 mem_fragmentation_ratio:0.59

Keyspace

db0:keys = 282,expires = 27,avg_ttl = 11335089640

這對於在任何特定時刻了解內存狀態和密鑰空間非常方便。

相關問題