2012-01-16 7 views
13

В приложении node.js я использую библиотеку очередей kue, которая поддерживается redis. Когда задание завершено, я удаляю его из очереди. После запуска около 70 000 заданий в ночное время использование памяти redis составляет около 30 МБ. В базе данных осталось 18 неудачных заданий, а длина очереди в настоящее время равна нулю - задания обрабатываются быстрее, чем они находятся в очереди. Redis не используется каким-либо другим способом.Использование библиотеки «kue» с redis-backed в node.js - почему использование 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. Для системы очередей, если вы ставите в очередь предметы быстрее, чем вы можете их деактивировать, у вас будет такой пик в потреблении памяти.

Моей рекомендацией было бы помочь вашему приложению получить и зарегистрировать длину очереди с регулярными интервалами времени, чтобы проверить эволюцию количества элементов в очереди (и определить максимальное значение).

Обновлено:

Я проверил несколько вещей с КУЭ, чтобы понять, что он хранит в 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: полный, несмотря на работу, были удалены. Я предлагаю вам проверить мощность этих 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.

+0

Hi Didier - спасибо за этот ответ, но я не думаю, что он идентифицирует проблему. Я должен был упомянуть, что длина очереди равна нулю. Легко контролировать статус очереди с помощью этой библиотеки kue - она ​​включает встроенный сервер администратора и интерфейс. Я отредактирую свой вопрос, чтобы добавить эту информацию. – mainsocial

+0

Я обновил свой ответ соответственно. –

+0

Дидье - спасибо за ваше расследование. Я самостоятельно пришел к такому же выводу. На самом деле были некоторые ошибки в коде kue, которые я смог исправить. Я проверил исправления на свою вилку и сделал запрос на тяну. – mainsocial

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

или

Ключевое слово

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

Это очень удобно для понимания состояния вашей памяти и пространства ключей в любой момент.

Смежные вопросы