Если у вас есть проблема с использованием памяти системой очередей, и вы на 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: jobs: complete и q: jobs: X: complete, несмотря на то, что задания были удалены. Я предлагаю вам проверить мощность этих zsets в вашем собственном экземпляре Redis.
Мое объяснение состоит в том, что управление этими zset происходит после того, как испущено 'завершенное' событие. Таким образом, задания корректно удаляются, но их идентификаторы вставляются в эти 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.